Browse Source

Try out structs as values.

Beoran 4 years ago
parent
commit
be78e79cf5
3 changed files with 87 additions and 0 deletions
  1. 61 0
      builtin.go
  2. 3 0
      parser.go
  3. 23 0
      value.go

+ 61 - 0
builtin.go

@@ -416,6 +416,64 @@ func exit(vm *VM, val ...Value) [] Value {
 	return Ok()
 }
 
+type Door struct {
+	name string
+	locked bool
+	opened bool
+}
+
+
+const DoorType = TypeValue("Door")
+
+func (door * Door) String() string {
+	return fmt.Sprintf("Door: %s %v %v", door.name, door.locked, door.opened)
+}
+
+
+func (*Door) Type() TypeValue {
+	return DoorType
+}
+
+func (from * Door) Convert(to interface{}) error {
+	switch toPtr := to.(type) {
+		case **Door:
+			(*toPtr) = from
+		case *Value:
+			(*toPtr) = from
+		default:
+			return NewErrorValuef("Cannot convert DoorValue value %v to %v", from, to)
+	}
+	return nil
+}
+
+func door(vm *VM, val ...Value) [] Value {
+	var name string
+	var locked bool
+	_, err := ParseOptArgs(val, 1, &name, &locked)
+	if err != nil {
+		Fail(err)
+	}
+	return Ok(&Door{name: name, locked: locked, opened:false})
+}
+
+func (door * Door) Open() {
+	door.opened = true
+}
+
+func openDoor(vm *VM, val ...Value) [] Value {
+	var door *Door
+	_, err := ParseArgs(val, &door)
+	if err != nil {
+		Fail(err)
+	}
+	if door == nil {
+		return Fail(NewErrorValuef("Door may not be nil."))
+	}	
+	
+	fmt.Printf("Door: %v %s", door, door)
+	door.Open()
+	return Ok(door)
+}
 
 func (vm *VM) RegisterBuiltins() {
 	vm.RegisterBuiltinWithHelp("addi", addi, `[Int Int] -> Int: adds two integers together`)
@@ -450,6 +508,9 @@ func (vm *VM) RegisterBuiltins() {
 	vm.RegisterBuiltin("help", help)
 	vm.RegisterBuiltin("explain", explain)
 	vm.RegisterBuiltin("exit", exit)
+	vm.RegisterBuiltin("door", door)
+	vm.RegisterBuiltin("openDoor", openDoor)
+	vm.AddOverloads("open", Over("openDoor", 0, DoorType))
 	
 	vm.AddOverloads("mul", 
 			Over("mulf", 0, FloatTypeValue, FloatTypeValue),

+ 3 - 0
parser.go

@@ -591,6 +591,9 @@ var DefaultKeywords []*Keyword = []*Keyword{
 	&Keyword { "so", TokenKindCloseParen, StringValue(")") },
 	&Keyword { "list", TokenKindOpenList, StringValue("[") },
 	&Keyword { "done", TokenKindCloseList, StringValue("]") },
+	&Keyword { "the", TokenKindGet, StringValue("$") },
+	&Keyword { "a", TokenKindGet, StringValue("$") },
+	&Keyword { "an", TokenKindGet, StringValue("$") },
 }
 
 

+ 23 - 0
value.go

@@ -396,6 +396,29 @@ func ParseArgs(args []Value, to...interface{}) ([]Value, error) {
 	return rest, nil
 }
 
+/* Helpers to easily convert Muesli value lists to "normal" Go values. 
+ * The returned array are the remaining unparsed arguments. */
+func ParseOptArgs(args []Value, required int, to...interface{}) ([]Value, error) {
+	if required > len(args) {
+		return nil, NewErrorValuef("Too few arguments, expected %d, got %d", required, len(args))
+	}
+	i:= 0
+	for ; i < len(to) && i < len(args) ; i ++ {
+		fromElt := args[i]
+		toElt 	:= to[i]
+		if fromElt == nil {
+			return nil, NewErrorValuef("Nil value in argument %d", i)
+		}
+		err := fromElt.Convert(toElt)
+		if err != nil {
+			return nil, err
+		}
+	}
+	rest := args[i:len(args)]
+	return rest, nil
+}
+
+
 /* Helpers to easily convert Muesli value lists to "normal" Go values in slices. */
 func ParseArgsToIntSlice(args []Value) ([]int, error) {
 	res := []int{}