Browse Source

Trying out building in Go struct types, and write helper for that. Considering giving all functions a fixed signature.

Beoran 4 years ago
parent
commit
e84756257c
5 changed files with 154 additions and 12 deletions
  1. 1 1
      ast.go
  2. 98 0
      builtin.go
  3. 15 0
      parser.go
  4. 27 9
      value.go
  5. 13 2
      vm.go

+ 1 - 1
ast.go

@@ -189,7 +189,7 @@ func (astkind AstMetaKindTarget) Eval(vm *VM, ast Ast, val ...Value) []Value {
 func (astkind AstMetaKindCommand) Eval(vm *VM, ast Ast, val ...Value) []Value {
 	commandName := ast.Value()	
 	arguments := val
-	// log.Printf("Command execute: %s %v", commandName.String(), arguments)
+	vm.Trace("Command execute: %s %v", commandName.String(), arguments)
 	res := vm.CallNamed(commandName.String(), arguments...)	
 	return res
 }

+ 98 - 0
builtin.go

@@ -416,6 +416,100 @@ func exit(vm *VM, val ...Value) [] Value {
 	return Ok()
 }
 
+type Door struct {
+	name string
+	locked bool
+	opened bool
+}
+
+// Implement callable ... 
+func (door * Door) Position() *Position {
+	return &Position{"builtin.go", 427, 8}
+}
+
+type ValueCallable interface {
+	Callable
+	Value
+}
+
+func Redispatch(from ValueCallable, vm *VM, args...Value) []Value {
+	if len(args) < 1 {
+		return EmptyValueArray()		
+	}
+	var word WordValue 
+	_, err := ParseOptArgs(args, 1, &word)
+	if err != nil {
+		return Fail(err)
+	}
+	args[0] = from
+	return vm.CallNamed(string(word), args...)
+} 
+
+func (door * Door) Call(vm *VM, args...Value) []Value {
+	return Redispatch(door, vm, args...)
+}
+
+var doorSignature = NewSignature(WordTypeValue) 
+
+func (door * Door) Signature() *Signature {
+    return &doorSignature
+}
+
+var _ Callable = &Door{}
+
+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 *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 {
+		return 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 {
+		return 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 +544,10 @@ 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.Register("Door", DoorType)
+	vm.AddOverloads("open", Over("openDoor", 0, DoorType))
 	
 	vm.AddOverloads("mul", 
 			Over("mulf", 0, FloatTypeValue, FloatTypeValue),

+ 15 - 0
parser.go

@@ -591,6 +591,21 @@ var DefaultKeywords []*Keyword = []*Keyword{
 	&Keyword { "so", TokenKindCloseParen, StringValue(")") },
 	&Keyword { "list", TokenKindOpenList, StringValue("[") },
 	&Keyword { "done", TokenKindCloseList, StringValue("]") },
+    &Keyword { "the", TokenKindGet, StringValue("$") },
+}
+
+var DefaultKeywordsFR []*Keyword = []*Keyword{
+	&Keyword { "vrai", TokenKindBoolean, TrueValue },
+	&Keyword { "faux", TokenKindBoolean, FalseValue },
+	&Keyword { "nul", TokenKindNil, NilValue },
+	&Keyword { "fais", TokenKindOpenBlock, StringValue("{") },
+	&Keyword { "fin", TokenKindCloseBlock, StringValue("}") },
+	&Keyword { "comme", TokenKindOpenParen, StringValue("(") },
+	&Keyword { "ça", TokenKindCloseParen, StringValue(")") },
+	&Keyword { "liste", TokenKindOpenList, StringValue("[") },
+	&Keyword { "fini", TokenKindCloseList, StringValue("]") },
+    &Keyword { "le", TokenKindGet, StringValue("$") },
+    &Keyword { "la", TokenKindGet, StringValue("$") },
 }
 
 

+ 27 - 9
value.go

@@ -96,8 +96,12 @@ func (val ListValue) String() string {
 	res := "["
 	sep := ""
 	for _, elt := range val.List {
-		res = res + sep + elt.String()
-		sep = ", "
+        if elt == nil {
+            res = res + sep + "nil"
+        } else   { 
+            res = res + sep + elt.String()
+        }
+        sep = ", "
 	}
 	res += "]"
 	return res
@@ -374,18 +378,25 @@ func From(from Value, to interface{}) error {
 	return from.Convert(to)
 }
 
-/* Helpers to easily convert Muesli value lists to "normal" Go values. 
- * The returned array are the remaining unparsed arguments. */
-func ParseArgs(args []Value, to...interface{}) ([]Value, error) {
-	if len(to) > len(args) {
-		return nil, NewErrorValuef("Too few arguments, expected %d, got %d", len(to), len(args))
+// ParseOptArgs ia helper to easily convert Muesli value lists to "normal" 
+// Go values. args is the input, required is the amount of required aruments, 
+// and to are pointers to where to store the data. The args are converted by 
+// calling the  Convert() method on them.
+// The returned array contains 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))
 	}
+    stop := len(args)
+    if len(to) < stop {
+        stop = len(to)
+    }
 	i:= 0
-	for ; i < len(to) ; i ++ {
+	for ; i < stop ; i ++ {
 		fromElt := args[i]
 		toElt 	:= to[i]
 		if fromElt == nil {
-			return nil, NewErrorValuef("Nil value in argument %d", i)
+			return nil, NewErrorValuef("Nil pointer to result %d", i)
 		}
 		err := fromElt.Convert(toElt)
 		if err != nil {
@@ -396,6 +407,13 @@ func ParseArgs(args []Value, to...interface{}) ([]Value, error) {
 	return rest, nil
 }
 
+
+// ParseArgs is helper to easily convert Muesli value lists to "normal" 
+// Go values.  It is the same as ParseOptArgs(args, len(to, to...)
+func ParseArgs(args []Value, to...interface{}) ([]Value, error) {
+	return ParseOptArgs(args, len(to), to...)
+}
+
 /* Helpers to easily convert Muesli value lists to "normal" Go values in slices. */
 func ParseArgsToIntSlice(args []Value) ([]int, error) {
 	res := []int{}

+ 13 - 2
vm.go

@@ -20,6 +20,8 @@ type Callable interface {
 	Call(vm *VM, arguments ...Value) []Value
 	// Callable has a position here it was defined. Needed for tracebacks.
 	Position() *Position
+    // Callable has a signature.. but not yet!
+    // Signature() *Signature
 }
 
 // A helper Value has a help text available.
@@ -164,7 +166,7 @@ func NewDefinedValue(name string, params []*Parameter, body *BlockValue) *Define
 }
 
 func (defined *DefinedValue) Call(vm *VM, arguments ...Value) []Value {
-	// vm.Logf("Call defined value: %v", defined)
+	vm.Trace("Call defined value: %v %v %v", defined, defined.Parameters, arguments)
     for i , arg := range arguments {
 		if i >= len(defined.Parameters) {
 			break
@@ -175,6 +177,7 @@ func (defined *DefinedValue) Call(vm *VM, arguments ...Value) []Value {
 			return Fail(NewErrorValuef("Argument %d type mismatch: %s<->%s", i, expectedType, arg.Type()))
 		}
 		vm.Register(param.Name.String(), arg)
+        vm.Trace("DefinedValue.Call: vm.Register: %v %v", param.Name.String(), arg)
 	}
 	
 	res := defined.Body.Call(vm, arguments...)
@@ -199,7 +202,7 @@ func (defined *DefinedValue) Help() string {
 */
 const TypesInSignature = 32
 
-/* A signature describes the desired types of an overloaded function call. */
+/* Signature describes the types that a callable takes. */
 type Signature struct {
 	Types [TypesInSignature]TypeValue
 }
@@ -217,6 +220,14 @@ func (s Signature) String() string {
 	return res
 }
 
+func NewSignature(types ... TypeValue) Signature {
+    signature := Signature{}
+    for i := 0 ; i < len(types) && i < len(signature.Types) ; i ++ {
+        signature.Types[i] = types[i]
+    }
+    return signature
+}
+
 func CalculateSignature(arguments ...Value) Signature {
 	signature := Signature{}
 	for i := 0; i < len(signature.Types); i++ {