|
@@ -1,7 +1,11 @@
|
|
// vm, the virtual low level machine that runs MUESLI.
|
|
// vm, the virtual low level machine that runs MUESLI.
|
|
package muesli
|
|
package muesli
|
|
|
|
|
|
-import "fmt"
|
|
|
|
|
|
+import (
|
|
|
|
+ "fmt"
|
|
|
|
+ "strings"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
|
|
// Handler function
|
|
// Handler function
|
|
type Handler func(vm *VM, arguments ...Value) []Value
|
|
type Handler func(vm *VM, arguments ...Value) []Value
|
|
@@ -514,7 +518,7 @@ func NewFrame(parent *Frame, position *Position) *Frame {
|
|
}
|
|
}
|
|
|
|
|
|
type Tracer interface {
|
|
type Tracer interface {
|
|
- Trace(vm VM, ast Ast, values ...Value) bool
|
|
|
|
|
|
+ Trace(vm VM, fmt string, args ... interface{}) bool
|
|
}
|
|
}
|
|
|
|
|
|
// Virtual machine
|
|
// Virtual machine
|
|
@@ -534,8 +538,15 @@ func NewVM() *VM {
|
|
return vm
|
|
return vm
|
|
}
|
|
}
|
|
|
|
|
|
-func (vm *VM) PushNewFrame(position *Position) *Frame {
|
|
|
|
|
|
+func (vm *VM) Trace(fm string, args ... interface{}) {
|
|
|
|
+ if vm.Tracer != nil {
|
|
|
|
+ vm.Tracer.Trace(*vm, fm, args...)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (vm *VM) PushNewFrame(position *Position) *Frame {
|
|
frame := NewFrame(vm.Frame, position)
|
|
frame := NewFrame(vm.Frame, position)
|
|
|
|
+ vm.Trace("PushFrame %v->%v\n", vm.Frame, frame)
|
|
vm.Frame = frame
|
|
vm.Frame = frame
|
|
return frame
|
|
return frame
|
|
}
|
|
}
|
|
@@ -552,9 +563,15 @@ func (vm *VM) Return(results ...Value) []Value {
|
|
|
|
|
|
|
|
|
|
func (vm *VM) PopFrame() *Frame {
|
|
func (vm *VM) PopFrame() *Frame {
|
|
|
|
+ oldFrame := vm.Frame
|
|
|
|
+ vm.Trace("PopFrame %v->%v\n", vm.Frame, vm.Frame.parent)
|
|
if (vm.Frame != vm.TopFrame) && (vm.Frame.parent != nil) {
|
|
if (vm.Frame != vm.TopFrame) && (vm.Frame.parent != nil) {
|
|
frame := vm.Frame
|
|
frame := vm.Frame
|
|
vm.Frame = frame.parent
|
|
vm.Frame = frame.parent
|
|
|
|
+ // Copy frame results up.
|
|
|
|
+ vm.Frame.returned = oldFrame.returned
|
|
|
|
+ vm.Frame.failed = oldFrame.failed
|
|
|
|
+ vm.Frame.results = oldFrame.results
|
|
return frame
|
|
return frame
|
|
}
|
|
}
|
|
return nil
|
|
return nil
|
|
@@ -624,15 +641,11 @@ func (vm *VM) AddTrace(err error) error {
|
|
}
|
|
}
|
|
|
|
|
|
func (vm *VM) CallCallable(callable Callable, arguments ...Value) []Value {
|
|
func (vm *VM) CallCallable(callable Callable, arguments ...Value) []Value {
|
|
- defer vm.PopFrame()
|
|
|
|
defer vm.PopScope()
|
|
defer vm.PopScope()
|
|
|
|
+ defer vm.PopFrame()
|
|
vm.PushNewFrame(callable.Position())
|
|
vm.PushNewFrame(callable.Position())
|
|
vm.PushNewScope()
|
|
vm.PushNewScope()
|
|
result := callable.Call(vm, arguments...)
|
|
result := callable.Call(vm, arguments...)
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
return result
|
|
return result
|
|
}
|
|
}
|
|
|
|
|
|
@@ -657,7 +670,7 @@ func (vm * VM) CallNamedFramed(name string, arguments ...) []Value {
|
|
*/
|
|
*/
|
|
|
|
|
|
// ScopeUp Returns the levelth scope up from the current one where 0 is the
|
|
// 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
|
|
|
|
|
|
+// current scope. Returns the toplevel scope if l is greater than the current
|
|
// scope stack depth.
|
|
// scope stack depth.
|
|
func (vm * VM) ScopeUp(level int) *Scope {
|
|
func (vm * VM) ScopeUp(level int) *Scope {
|
|
scope := vm.Scope
|
|
scope := vm.Scope
|
|
@@ -814,13 +827,16 @@ func (vm *VM) RunAst(ast Ast, args ...Value) []Value {
|
|
result = ast.Eval(vm)
|
|
result = ast.Eval(vm)
|
|
if vm.Frame.returned || vm.Frame.failed {
|
|
if vm.Frame.returned || vm.Frame.failed {
|
|
result = vm.Frame.results
|
|
result = vm.Frame.results
|
|
|
|
+ vm.Frame.returned = false
|
|
|
|
+ vm.Frame.failed = false
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
var subResult = []Value{}
|
|
var subResult = []Value{}
|
|
// Depth first recursion.
|
|
// Depth first recursion.
|
|
- for _, child := range ast.Children() {
|
|
|
|
|
|
+ for i, child := range ast.Children() {
|
|
sub := vm.RunAst(*child)
|
|
sub := vm.RunAst(*child)
|
|
subResult = append(subResult, sub...)
|
|
subResult = append(subResult, sub...)
|
|
|
|
+ vm.Trace("RunAst: %d %v %v %v\n", i, child, sub, vm.Frame)
|
|
/*
|
|
/*
|
|
if frame.failed && frame.parent != nil {
|
|
if frame.failed && frame.parent != nil {
|
|
// failures are like panics and propagate up the call tree
|
|
// failures are like panics and propagate up the call tree
|
|
@@ -831,6 +847,8 @@ func (vm *VM) RunAst(ast Ast, args ...Value) []Value {
|
|
|
|
|
|
if vm.Frame.returned || vm.Frame.failed {
|
|
if vm.Frame.returned || vm.Frame.failed {
|
|
subResult = vm.Frame.results
|
|
subResult = vm.Frame.results
|
|
|
|
+ vm.Frame.returned = false
|
|
|
|
+ vm.Frame.failed = false
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -846,6 +864,39 @@ func (vm *VM) DefinedHelpers() []Helper {
|
|
return vm.Scope.DefinedHelpers()
|
|
return vm.Scope.DefinedHelpers()
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func (vm * VM) BackTraceFrames() []*Frame {
|
|
|
|
+ bt := []*Frame{}
|
|
|
|
+
|
|
|
|
+ for frame := vm.Frame ; frame.parent != nil ; frame = frame.parent {
|
|
|
|
+ bt = append(bt, frame)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return bt
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (vm * VM) BackTracePositions() []*Position {
|
|
|
|
+ bt := []*Position{}
|
|
|
|
+
|
|
|
|
+ for frame := vm.Frame ; frame.parent != nil ; frame = frame.parent {
|
|
|
|
+ bt = append(bt, frame.position)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return bt
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (vm * VM) BackTraceStrings() []string {
|
|
|
|
+ bt := []string{}
|
|
|
|
+
|
|
|
|
+ for frame := vm.Frame ; frame.parent != nil ; frame = frame.parent {
|
|
|
|
+ bt = append(bt, frame.position.String())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return bt
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (vm * VM) BackTrace() string {
|
|
|
|
+ return strings.Join(vm.BackTraceStrings(), "\n")
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
/*
|
|
/*
|