Browse Source

Helper for making objcts callable.

Beoran 4 years ago
parent
commit
9024375ca5
3 changed files with 92 additions and 40 deletions
  1. 18 32
      builtin.go
  2. 68 3
      value.go
  3. 6 5
      vm.go

+ 18 - 32
builtin.go

@@ -99,11 +99,8 @@ func sumf(vm *VM, args ...Value) []Value {
 
 func addi(vm *VM, args ...Value) []Value {
 	var v1, v2 int
-	_, err := ParseArgs(args, &v1, &v2)
-	if err != nil {
-		return Fail(err)
-	}	
-	return IntOk(v1 + v2)
+	ParseArgs(args, &v1, &v2)
+    return IntOk(v1 + v2)
 }
 
 
@@ -302,6 +299,9 @@ func fetchl(vm *VM, args ...Value) []Value {
 	if err != nil {
 		return Fail(err)
 	}
+    if (index < 0) || (index >= len(list.List)) {
+        return Fail(fmt.Errorf("index out of range: %d<->%d", index, len(list.List)))
+    } 
 	return Ok(list.List[index])	
 }
 
@@ -312,9 +312,12 @@ func storel(vm *VM, args ...Value) []Value {
 	if err != nil {
 		return Fail(err)
 	}
-	if len (rest) < 1 {
+	if len(rest) < 1 {
 		return Fail(fmt.Errorf("fetch: need 3 arguments")) 
-	}	
+	}
+    if (index < 0) || (index >= len(list.List)) {
+        return Fail(fmt.Errorf("index out of range: %d<->%d", index, len(list.List)))
+    }
 	list.List[index] = rest[0]
 	return Ok(list.List[index])	
 }
@@ -421,23 +424,6 @@ func (door * Door) Position() *Position {
 	return &Position{"builtin.go", 427, 8}
 }
 
-type CallableValue interface {
-	Callable
-	Value
-}
-
-func Redispatch(from CallableValue, 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...)
@@ -512,15 +498,15 @@ func (vm *VM) RegisterBuiltins() {
 	vm.RegisterBuiltin("cover", cover)
 	vm.RegisterBuiltin("fetchl", fetchl)
 	vm.RegisterBuiltin("fetchm", fetchm)
-	vm.RegisterBuiltin("sumi", sumi)
-	vm.RegisterBuiltin("sumf", sumf)
-	vm.RegisterBuiltin("subi", subi)
-	vm.RegisterBuiltin("subf", subf)
-	vm.RegisterBuiltin("divi", divi)
-	vm.RegisterBuiltin("divf", divf)
+	vm.RegisterBuiltin("sumi", sumi).Takes(IntType, IntType).Returns(IntType)
+	vm.RegisterBuiltin("sumf", sumf).Takes(FloatType, FloatType).Returns(FloatType)
+	vm.RegisterBuiltin("subi", subi).Takes(IntType, IntType).Returns(IntType)
+	vm.RegisterBuiltin("subf", subf).Takes(FloatType, FloatType).Returns(FloatType)
+	vm.RegisterBuiltin("divi", divi).Takes(IntType, IntType).Returns(IntType)
+	vm.RegisterBuiltin("divf", divf).Takes(FloatType, FloatType).Returns(FloatType)
 	vm.RegisterBuiltin("map", newmap)
-	vm.RegisterBuiltin("muli", muli)
-	vm.RegisterBuiltin("mulf", mulf)
+	vm.RegisterBuiltin("muli", muli).Takes(IntType, IntType).Returns(IntType)
+	vm.RegisterBuiltin("mulf", mulf).Takes(FloatType, FloatType).Returns(FloatType)
 	vm.RegisterBuiltinWithHelp("orb", orb, `[Bool Bool] -> Bool: returns true if on of it's arguments is true`)
 	// vm.RegisterCover("add")
 	vm.RegisterBuiltin("p", p)

+ 68 - 3
value.go

@@ -27,6 +27,7 @@ type EmptyValue struct {
 }
 
 type ListValue struct {
+    RedispatchCallable
 	List []Value
 }
 
@@ -136,7 +137,7 @@ func NewErrorValuef(format string, args ...interface{}) ErrorValue {
 }
 
 func NewListValue(elements ...Value) * ListValue {
-	return &ListValue{elements}
+	return &ListValue{ NewRedispatchCallable(), elements}
 }
 
 func (list *ListValue) Append(elements ...Value) {
@@ -176,7 +177,7 @@ func (list *ListValue) Last() Value {
 
 
 func EmptyListValue() ListValue {
-	return ListValue{make([]Value, 0)}
+	return ListValue{NewRedispatchCallable(), make([]Value, 0)}
 }
 
 func EmptyValueArray() []Value {
@@ -408,7 +409,7 @@ func ParseOptArgs(args []Value, required int, to...interface{}) ([]Value, error)
 }
 
 // ParseArgs is helper to easily convert Muesli value lists to "normal" 
-// Go values.  It is the same as ParseOptArgs(args, len(to, to...)
+// 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...)
 }
@@ -539,3 +540,67 @@ func FloatOk(f float64) []Value{
 	return []Value{FloatValue(f)}
 }
 
+
+// CallableValue is is both a Value and a Callable.
+type CallableValue interface {
+	Callable
+	Value
+}
+
+// Redispath takes the first argument i args, and if that is a word,
+// calls the command named by that word, replacing the from CalableValue
+// as the first argument. This allows some OOP style trickery where
+// custom_value foo gets called as foo custom_value where custom_value is 
+// of CustomType. 
+// In this case foo should the be an overloaded command that takes CustomType.  
+func Redispatch(from CallableValue, 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...)
+} 
+
+
+// RedispatchCallable can be embedded into a type to allow it to 
+// become redispatchable, that is, it can support OOP style
+// calling of pseudo methods by rearranging the command.  
+type RedispatchCallable struct {
+    BasicCallable
+}
+
+func (rc * RedispatchCallable) Call(vm *VM, args...Value) []Value {
+	return Redispatch(rc, vm, args...)
+}
+
+var _ Callable = &RedispatchCallable{}
+
+func NewRedispatchCallable() RedispatchCallable {
+    return RedispatchCallable{}
+}
+
+// Implement callable ... 
+/*
+func (list * ListValue) Position() *Position {
+	return &Position{"value.go", 572, 8}
+}
+
+
+func (list * ListValue) Call(vm *VM, args...Value) []Value {
+	return Redispatch(list, vm, args...)
+}
+
+var listSignature = NewSignature(WordType, IntType) 
+
+func (list * ListValue) Signature() Signature {
+    return listSignature
+}
+*/
+
+var _ Callable = &ListValue{}
+

+ 6 - 5
vm.go

@@ -39,8 +39,10 @@ type BasicCallable struct {
 	Name string
 	// Help string for the callable.
 	HelpText string
-	// Signature of the callable
-	signature Signature 
+	// Signature of the callable for type checking.
+	signature Signature
+    // Position where the callable is defined.
+    position Position
 }
 
 func (val BasicCallable) Signature() Signature {
@@ -106,7 +108,7 @@ type BuiltinValue struct {
 }
 
 func NewBasicCallable(name string) BasicCallable {
-	return BasicCallable{name, "", NoSignature()}
+	return BasicCallable{name, "", NoSignature(), Position{name, 1, 1}}
 }
 
 
@@ -154,8 +156,7 @@ func (defined * DefinedValue) Position() *Position {
 }
 
 func (cv BasicCallable) Position() *Position {
-	pos := Position{cv.Name, 1, 1}
-	return &pos
+	return &cv.position
 }
 
 // A script defined function