Browse Source

WIP return or fail.

Beoran 4 years ago
parent
commit
ad6c510461
4 changed files with 189 additions and 70 deletions
  1. 18 9
      builtin.go
  2. 3 0
      value.go
  3. 155 48
      vm.go
  4. 13 13
      vm_test.go

+ 18 - 9
builtin.go

@@ -202,6 +202,12 @@ func val(vm *VM, args ...Value) []Value {
 	return args
 }
 
+func builtin_return(vm *VM, args ...Value) []Value {
+	vm.Frame.returned = true
+	vm.Frame.results = args
+	return args
+}
+
 func to(vm *VM, args ...Value) []Value {
 	var name string	
 	rest, err := ParseArgs(args, &name)
@@ -234,7 +240,8 @@ func to(vm *VM, args ...Value) []Value {
 		defpars = append(defpars, par) 
 	}
 	
-	return Ok(vm.RegisterDefined(name, defpars, block))
+	// To must register one level up.
+	return Ok(vm.RegisterDefined(name, defpars, block, 1))
 }
 
 func cover(vm *VM, args ...Value) []Value {
@@ -251,7 +258,8 @@ func cover(vm *VM, args ...Value) []Value {
 			return Fail(NewErrorValuef("Argument %d: not a type: %v %s", i+2, arg, arg.String()))
 		}
 	}	
-	err = vm.AddOverload(name, target, types...)
+	// Overload must be defined one scope up.
+	err = vm.AddOverload(name, target, 1, types...)
 	
 	if err != nil {
 		return Fail(err)
@@ -282,7 +290,7 @@ func set(vm *VM, val ...Value) []Value {
 		target = val[1].String() 
 		value = val[2]
 	}	
-	vm.Register(target, value)
+	vm.RegisterUp(target, value, 1)
 	return Ok(value)
 }
 
@@ -438,6 +446,7 @@ func (vm *VM) RegisterBuiltins() {
 	vm.RegisterBuiltin("trace", trace)
 	vm.RegisterBuiltin("to", to)
 	vm.RegisterBuiltin("types", types)
+	vm.RegisterBuiltin("return", builtin_return)
 	vm.RegisterBuiltin("val", val)
 	vm.RegisterBuiltin("set", set)
 	vm.RegisterBuiltin("get", get)
@@ -446,15 +455,15 @@ func (vm *VM) RegisterBuiltins() {
 	vm.RegisterBuiltin("exit", exit)
 	
 	vm.AddOverloads("mul", 
-			Over("mulf", FloatTypeValue, FloatTypeValue),
-			Over("muli", IntTypeValue, IntTypeValue),
-			Over("mulf", FloatTypeValue, IntTypeValue),
-			Over("mulf", FloatTypeValue, IntTypeValue))
+			Over("mulf", 0, FloatTypeValue, FloatTypeValue),
+			Over("muli", 0, IntTypeValue, IntTypeValue),
+			Over("mulf", 0, FloatTypeValue, IntTypeValue),
+			Over("mulf", 0, FloatTypeValue, IntTypeValue))
 			
 	vm.SetHelp("mul", "	 Num: Multiplies two numbers. Cover for muli and mulf.")	
 	vm.AddOverloads("fetch", 
-			Over("fetchl", ListTypeValue, IntTypeValue),
-			Over("fetchm", MapTypeValue, AnyTypeValue),
+			Over("fetchl", 0, ListTypeValue, IntTypeValue),
+			Over("fetchm", 0, MapTypeValue, AnyTypeValue),
 		)			
 	vm.SetHelp("fetch", " storage, index. Fetch value in storage at given index.")
 	/*

+ 3 - 0
value.go

@@ -384,6 +384,9 @@ func ParseArgs(args []Value, to...interface{}) ([]Value, error) {
 	for ; i < len(to) ; 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

+ 155 - 48
vm.go

@@ -10,9 +10,12 @@ func (handler *Handler) Call(vm *VM, arguments ...Value) []Value {
 	return (*handler)(vm, arguments...)
 }
 
-// A callable Value must implement the Caller interface
-type Caller interface {
+// A callable Value must implement the Callable interface
+type Callable interface {
+	// Callable can be called
 	Call(vm *VM, arguments ...Value) []Value
+	// Callable has a position here it was defined. Needed for tracebacks.
+	Position() *Position
 }
 
 // A helper Value has a help text available.
@@ -92,10 +95,6 @@ func NewBuiltinValue(name string, handler Handler) *BuiltinValue {
 	return result
 }
 
-func (builtin *BuiltinValue) Call(vm *VM, arguments ...Value) []Value {
-	return vm.CallBuiltin(builtin.Handler, arguments...)
-}
-
 // A block in a script.
 type BlockValue struct {
 	CallableValue
@@ -109,9 +108,32 @@ func NewBlockValue(definition *Ast) *BlockValue {
 	return result
 }
 
-func (block *BlockValue) Call(vm *VM, arguments ...Value) []Value {
-	res := vm.CallBlock(block.Ast, arguments...)
-	return res
+func (block * BlockValue) Position() *Position {
+	if block == nil {
+		return nil
+	}
+
+	if block.Ast == nil {
+		return nil
+	}	
+	pos := block.Ast.Token().Position
+	return &pos
+}
+
+func (defined * DefinedValue) Position() *Position {
+	if defined == nil {
+		return nil
+	}
+
+	if defined.Body == nil {
+		return nil
+	}	
+	return defined.Body.Position()
+}
+
+func (cv CallableValue) Position() *Position {
+	pos := Position{cv.Name, 1, 1}
+	return &pos
 }
 
 
@@ -123,7 +145,7 @@ type Parameter struct {
 
 
 // A script defined function
-type DefinedValue struct {
+type DefinedValue struct {	
 	CallableValue
 	Body *BlockValue
 	Parameters []*Parameter
@@ -138,10 +160,6 @@ func NewDefinedValue(name string, params []*Parameter, body *BlockValue) *Define
 }
 
 func (defined *DefinedValue) Call(vm *VM, arguments ...Value) []Value {
-	defer vm.PopFrame()
-	defer vm.PopScope()
-	vm.PushNewFrame()
-	vm.PushNewScope()
 	for i , arg := range arguments {
 		if i >= len(defined.Parameters) {
 			break
@@ -230,7 +248,7 @@ func (signature Signature) IsMatch(other Signature) bool {
 /* An overload is an overloaded value that can be called. */
 type Overload struct {
 	Name string
-	Caller
+	Callable
 }
 
 /* A cover is a callable that dispatches to other callables depending on
@@ -283,7 +301,7 @@ func (cover *CoverValue) Call(vm *VM, arguments ...Value) []Value {
 		}
 	}
 	vm.Fail()
-	return Fail(NewErrorValuef("Could not match cover %s with arguments: %s<->%v", cover.String(), signature))
+	return Fail(NewErrorValuef("Could not match cover %s with arguments: %s<->%v", cover.String(), signature, arguments))
 }
 
 const (
@@ -319,7 +337,7 @@ func (from BlockValue) Convert(to interface{}) error {
 }
 
 
-func (cv * CoverValue) AddOverload(name string, callable Caller, tv ... TypeValue) error {
+func (cv * CoverValue) AddOverload(name string, callable Callable, tv ... TypeValue) error {
 	// fmt.Printf("AddOverload: %v\n", tv)
 	
 	signature := Signature{}
@@ -332,20 +350,20 @@ func (cv * CoverValue) AddOverload(name string, callable Caller, tv ... TypeValu
 		signature.Types[i] = tv[i]
 	}
 		
-	cv.Overloads[signature] = Overload { Name: name, Caller: callable } 
+	cv.Overloads[signature] = Overload { Name: name, Callable: callable } 
 	
 	// fmt.Printf("Overloads: %v\n", cv.Overloads)
 	
 	return nil
 }
 
-func (vm * VM) AddOverload(from, target string, tv... TypeValue) error {
+func (vm * VM) AddOverload(from, target string, level int, tv... TypeValue) error {
 	var cover *CoverValue
-	var callable Caller
+	var callable Callable
 	var ok bool	
 	lookup := vm.Lookup(from)
 	if lookup == nil { 
-		cover = vm.RegisterCover(from)
+		cover = vm.RegisterCover(from, level)
 	} else if cover, ok = lookup.(*CoverValue) ; !ok {
 		return fmt.Errorf("%s exists and is not a cover value", from)
 	}
@@ -358,7 +376,7 @@ func (vm * VM) AddOverload(from, target string, tv... TypeValue) error {
 	}
 	// fmt.Printf("AddOverload lookup: %v\n", lookup)
 	
-	if callable, ok = lookup.(Caller) ; !ok {
+	if callable, ok = lookup.(Callable) ; !ok {
 		return fmt.Errorf("%s is not a callable value", target)
 	}
 	res := cover.AddOverload(target, callable, tv...)
@@ -371,11 +389,12 @@ func (vm * VM) AddOverload(from, target string, tv... TypeValue) error {
 type OverloadDescription struct {
 	Target string
 	Types []TypeValue
+	Level int
 }
 
 func (vm * VM) AddOverloads(from string, descriptions ... OverloadDescription) error {
 	for _, od := range descriptions {
-		err := vm.AddOverload(from, od.Target, od.Types...)
+		err := vm.AddOverload(from, od.Target, od.Level, od.Types...)
 		if err != nil {
 			panic(fmt.Errorf("internal error: could not register overloads: %s", err))
 		}
@@ -383,8 +402,8 @@ func (vm * VM) AddOverloads(from string, descriptions ... OverloadDescription) e
 	return nil
 }
 
-func Over(target string, types ... TypeValue) OverloadDescription {
-	return OverloadDescription { Target: target, Types: types}
+func Over(target string, level int, types ... TypeValue) OverloadDescription {
+	return OverloadDescription { Target: target, Level: level, Types: types}
 }
 
 func (vm * VM) SetHelp(target, help string) error {
@@ -412,17 +431,6 @@ func NewScope(parent *Scope) *Scope {
 	return &Scope{parent, make([]*Scope, 0), make(map[string]Value)}
 }
 
-func (scope *Scope) Parent(level int) *Scope {
-	if level < 1 {
-		return scope
-	}
-	parent := scope.parent
-	for parent != nil && level > 1 {
-		level--
-		parent = parent.parent
-	}
-	return parent
-}
 
 func (scope *Scope) Lookup(name string) Value {
 	value, ok := scope.symbols[name]
@@ -491,15 +499,17 @@ func (scope* Scope) DefinedHelpers() []Helper {
 
 
 // Frame of execution of a function
-type Frame struct {
+type Frame struct {	
 	parent    *Frame
 	arguments []Value
 	results   []Value
 	failed    bool
+	returned  bool
+	position  *Position
 }
 
-func NewFrame(parent *Frame) *Frame {
-	return &Frame{parent, EmptyValueArray(), EmptyValueArray(), false}
+func NewFrame(parent *Frame, position *Position) *Frame {
+	return &Frame{parent, EmptyValueArray(), EmptyValueArray(), false, false, position}
 }
 
 type Tracer interface {
@@ -517,14 +527,14 @@ type VM struct {
 }
 
 func NewVM() *VM {
-	vm := &VM{NewScope(nil), NewFrame(nil), nil, nil, nil, 0}
+	vm := &VM{NewScope(nil), NewFrame(nil, nil), nil, nil, nil, 0}
 	vm.Scope = vm.TopScope
 	vm.Frame = vm.TopFrame
 	return vm
 }
 
-func (vm *VM) PushNewFrame() *Frame {
-	frame := NewFrame(vm.Frame)
+func (vm *VM) PushNewFrame(position *Position) *Frame {
+	frame := NewFrame(vm.Frame, position)
 	vm.Frame = frame
 	return frame
 }
@@ -535,10 +545,23 @@ func (vm *VM) PushNewScope() *Scope {
 	return scope
 }
 
+func (vm *VM) Return(results ...Value) []Value {
+	return results
+}
+
+
 func (vm *VM) PopFrame() *Frame {
 	if (vm.Frame != vm.TopFrame) && (vm.Frame.parent != nil) {
 		frame := vm.Frame
+		if frame.returned || frame.failed {
+			
+		}
+		
+		
 		vm.Frame = frame.parent
+		vm.Frame.returned = frame.returned
+		vm.Frame.failed = frame.failed
+		vm.Frame.results = frame.results
 		return frame
 	}
 	return nil
@@ -553,6 +576,18 @@ func (vm *VM) PopScope() *Scope {
 	return nil
 }
 
+func (block * BlockValue) Call(vm *VM, arguments ...Value) []Value {
+	ast := block.Ast
+	arr := vm.RunChildren(*ast, arguments...)
+	return arr
+}
+
+func (builtin * BuiltinValue) Call(vm *VM, arguments ...Value) []Value {
+	handler := builtin.Handler
+	return handler.Call(vm, arguments...)
+}
+
+/*
 func (vm *VM) CallDefined(ast *Ast, arguments ...Value) []Value {	
 	arr := vm.RunChildren(*ast, arguments...)
 	return arr
@@ -570,9 +605,42 @@ func (vm *VM) CallBuiltin(handler Handler, arguments ...Value) []Value {
 func (vm *VM) CallCover(cover * CoverValue, arguments ...Value) []Value {
 	return cover.Call(vm, arguments...)
 }
+*/
 
 
+func (vm *VM) AddTrace(err error) error {
+	res := ""
+	for frame := vm.Frame; frame != nil; frame = frame.parent {
+		if frame.position == nil {
+			res = fmt.Sprintf("%s\nIn frame %v", res, frame)
+		} else {
+			res = fmt.Sprintf("%s\nIn %s", res, frame.position.String())
+		}
+	}
+	return fmt.Errorf("%s: %s", res, err)
+}
+
+func (vm *VM) CallCallable(callable Callable, arguments ...Value) []Value {
+	defer vm.PopFrame()
+	defer vm.PopScope()
+	vm.PushNewFrame(callable.Position())
+	vm.PushNewScope()
+	return callable.Call(vm, arguments...)
+}
+
 func (vm *VM) CallNamed(name string, arguments ...Value) []Value {
+	value := vm.Lookup(name)
+	if value == nil {
+		return ReturnError(vm.AddTrace(NewErrorValuef("Cannot call %s: not found.", name)))
+	}
+	
+	if callable, ok := value.(Callable) ; ok {
+		return vm.CallCallable(callable, arguments...)
+	} else {
+		return ReturnError(vm.AddTrace(NewErrorValuef("Cannot call %s: %v. Not callable", name, value)))
+	}
+	
+	/*
 	value := vm.Lookup(name)
 	switch toCall := value.(type) {
 	case *BuiltinValue:
@@ -584,8 +652,9 @@ func (vm *VM) CallNamed(name string, arguments ...Value) []Value {
 	case *BlockValue:
 		return vm.CallBlock(toCall.Ast, arguments...)	
 	default:
-		return ReturnError(NewErrorValuef("Cannot call %s: %v", name, value))
+		return ReturnError(vm.AddTrace(NewErrorValuef("Cannot call %s: %v. Not callable", name, value)))
 	}
+	*/
 }
 
 /*
@@ -595,13 +664,34 @@ func (vm * VM) CallNamedFramed(name string, arguments ...) []Value {
 }
 */
 
+// ScopeUp Returns the levelth scope up from the current one where 0 is the 
+// current scope. Returns the toplevel scope if l is greather than the current 
+// scope stack depth.
+func (vm * VM) ScopeUp(level int) *Scope {
+	scope := vm.Scope
+	for now := 0; now < level; now++ {
+		if scope.parent == nil {
+			return scope
+		}
+		scope = scope.parent
+	}
+	return scope
+}
+
+// RegisterUp registers in klevel scopes up from the current scope, 
+// or at toplevel if the level is greater than the total depth
+func (vm *VM) RegisterUp(name string, value Value, level int) Value {
+	scope := vm.ScopeUp(level)	
+	return scope.Register(name, value)
+}
+
 func (vm *VM) Register(name string, value Value) Value {
 	return vm.Scope.Register(name, value)
 }
 
-func (vm *VM) RegisterCover(name string) *CoverValue {
+func (vm *VM) RegisterCover(name string, level int) *CoverValue {
 	value := NewCoverValue(name)
-	vm.Register(name, value)
+	vm.RegisterUp(name, value, level)
 	return value
 }
 
@@ -610,9 +700,9 @@ func (vm *VM) RegisterBuiltin(name string, handler Handler) Value {
 	return vm.Register(name, value)
 }
 
-func (vm *VM) RegisterDefined(name string, params []*Parameter, block *BlockValue) Value {
+func (vm *VM) RegisterDefined(name string, params []*Parameter, block *BlockValue, level int) Value {
 	value := NewDefinedValue(name, params, block)
-	return vm.Register(name, value)
+	return vm.RegisterUp(name, value, level)
 }
 
 // RegisterBuiltinWithHelp
@@ -638,6 +728,11 @@ func (vm *VM) RunChildren(ast Ast, args ...Value) []Value {
 	for _, child := range ast.Children() {
 		val := child.Run(vm, args...)
 		
+		if vm.Frame.returned || vm.Frame.failed {
+			fmt.Printf("Returned.\n")
+			return vm.Frame.results
+		}
+		
 		// skip empty results
 		if len(val) < 1  {
 			continue
@@ -663,6 +758,12 @@ func (vm *VM) RunChildrenLastResult(ast Ast, args ...Value) Value {
 	var result Value = EmptyValue{}
 	for _, child := range ast.Children() {
 		val := child.Run(vm, args...)
+		
+		if vm.Frame.returned || vm.Frame.failed {
+			fmt.Printf("Returned.\n")
+			res := vm.Frame.results
+			return res[len(res)-1]
+		}
 				
 		// skip empty results
 		if len(val) < 1  {
@@ -690,7 +791,13 @@ func (vm *VM) RunChildrenFirstResult(ast Ast, args ...Value) Value {
 	var result Value = EmptyValue{}
 	for _, child := range ast.Children() {
 		val := child.Run(vm, args...)
-				
+		
+		if vm.Frame.returned || vm.Frame.failed {
+			fmt.Printf("Returned.\n")
+			res := vm.Frame.results
+			return res[0]
+		}
+						
 		// skip empty results
 		if len(val) < 1  {
 			continue

+ 13 - 13
vm_test.go

@@ -7,21 +7,21 @@ import (
 
 func TestVm1(test *testing.T) {
 	vm := NewVM()
-	bi := vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) ListValue {
+	bi := vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) []Value {
 		fmt.Printf("I am foo. See me foo?")
-		return NewListValue()
+		return []Value{}
 	})
 
 	if vm == nil {
 		test.Errorf("Could not construct VM")
 	}
 
-	if _, ok := bi.(BuiltinValue); !ok {
+	if _, ok := bi.(*BuiltinValue); !ok {
 		test.Errorf("Could not construct register a builtin function.")
 	}
 
 	foo := vm.Lookup("foo")
-	biv, ok := foo.(BuiltinValue)
+	biv, ok := foo.(*BuiltinValue)
 	if foo == nil || !ok {
 		test.Errorf("Could not look up foo.")
 	}
@@ -32,13 +32,13 @@ func TestVm1(test *testing.T) {
 
 func ExampleVm1() {
 	vm := NewVM()
-	vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) ListValue {
+	vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) []Value {
 		fmt.Printf("I am foo. See me foo?")
-		return NewListValue()
+		return []Value{}
 	})
 
 	foo := vm.Lookup("foo")
-	biv, ok := foo.(BuiltinValue)
+	biv, ok := foo.(*BuiltinValue)
 	if foo == nil || !ok {
 		fmt.Println("Could not look up foo.")
 	}
@@ -50,11 +50,11 @@ func ExampleVm1() {
 
 func ExampleVm2() {
 	vm := NewVM()
-	vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) ListValue {
+	vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) []Value {
 		var s string
 		From(args[0], &s)
 		fmt.Printf("I am foo. See me %s?", s)
-		return NewListValue()
+		return []Value{}
 	})
 
 	//Output: I am foo. See me bar?
@@ -64,7 +64,7 @@ func ExampleVm2() {
 
 func ExampleVm3() {
 	vm := NewVM()
-	vm.RegisterBuiltin("multi", func(vm *VM, args ...Value) ListValue {
+	vm.RegisterBuiltin("multi", func(vm *VM, args ...Value) []Value {
 		var one string
 		var two int64
 		err := ListFrom(args, &one, &two)
@@ -72,7 +72,7 @@ func ExampleVm3() {
 			fmt.Printf("Error: %s", err.Error())
 		}
 		fmt.Printf("I am multi. See me %s, %d?", one, two)
-		return NewListValue()
+		return []Value{}
 	})
 
 	//Output: I am multi. See me bar, 7?
@@ -82,7 +82,7 @@ func ExampleVm3() {
 
 func ExampleVm4() {
 	vm := NewVM()
-	vm.RegisterBuiltin("printf", func(vm *VM, args ...Value) ListValue {
+	vm.RegisterBuiltin("printf", func(vm *VM, args ...Value) []Value {
 		var form string
 		var rest = args[1:len(args)]
 		resri := ListFromList(rest)
@@ -92,7 +92,7 @@ func ExampleVm4() {
 		} else {
 			fmt.Printf(form, resri...)
 		}
-		return NewListValue()
+		return []Value{}
 	})
 
 	//Output: printf 7