Browse Source

Starting to become runnable.

Beoran 4 years ago
parent
commit
5e6a17f72a
12 changed files with 405 additions and 122 deletions
  1. 123 48
      ast.go
  2. 47 0
      builtin.go
  3. 86 0
      cmd/muesli/main.go
  4. 13 14
      design_muesli.muesli
  5. 3 1
      go.mod
  6. 4 0
      go.sum
  7. 38 27
      parser.go
  8. 6 5
      parser_test.go
  9. 6 3
      token.go
  10. 19 0
      value.go
  11. 48 14
      vm.go
  12. 12 10
      vm_test.go

+ 123 - 48
ast.go

@@ -4,6 +4,7 @@ package muesli
 import (
 import (
 	"fmt"
 	"fmt"
 	"strings"
 	"strings"
+	"log"
 )
 )
 
 
 type AstBasicMetaKind string
 type AstBasicMetaKind string
@@ -39,21 +40,21 @@ const (
 	AstKindProgram     = AstMetaKindProgram("Program")
 	AstKindProgram     = AstMetaKindProgram("Program")
 	AstKindStatements  = AstMetaKindStatements("Statements")
 	AstKindStatements  = AstMetaKindStatements("Statements")
 	AstKindStatement   = AstMetaKindStatement("Statement")
 	AstKindStatement   = AstMetaKindStatement("Statement")
-    AstKindClosed      = AstMetaKindSet("Closed")
+    // AstKindClosed      = AstMetaKindClosed("Closed")
 	AstKindSet         = AstMetaKindSet("Set")
 	AstKindSet         = AstMetaKindSet("Set")
 	AstKindGet         = AstMetaKindGet("Get")
 	AstKindGet         = AstMetaKindGet("Get")
 	AstKindTarget      = AstMetaKindTarget("Target")
 	AstKindTarget      = AstMetaKindTarget("Target")
 	AstKindCommand     = AstMetaKindCommand("Command")
 	AstKindCommand     = AstMetaKindCommand("Command")
 	AstKindArguments   = AstMetaKindArguments("Arguments")
 	AstKindArguments   = AstMetaKindArguments("Arguments")
-	AstKindArgument    = AstMetaKindArgument("Argument")
-	AstKindExpression  = AstMetaKindExpression("Expression")
+	// AstKindArgument    = AstMetaKindArgument("Argument")
+	// AstKindExpression  = AstMetaKindExpression("Expression")
 	AstKindBlock       = AstMetaKindBlock("Block")
 	AstKindBlock       = AstMetaKindBlock("Block")
 	AstKindParenthesis = AstMetaKindParenthesis("Parenthesis")
 	AstKindParenthesis = AstMetaKindParenthesis("Parenthesis")
 	AstKindList        = AstMetaKindList("List")
 	AstKindList        = AstMetaKindList("List")
-	AstKindCapture     = AstMetaKindCapture("Capture")
+	// AstKindCapture     = AstMetaKindCapture("Capture")
 	AstKindWordValue   = AstMetaKindWordValue("WordValue")
 	AstKindWordValue   = AstMetaKindWordValue("WordValue")
 	AstKindWord        = AstMetaKindWord("Word")
 	AstKindWord        = AstMetaKindWord("Word")
-	AstKindType        = AstMetaKindType("Type")
+	// AstKindType        = AstMetaKindType("Type")
 	AstKindValue       = AstMetaKindValue("Value")
 	AstKindValue       = AstMetaKindValue("Value")
 	AstKindEnd         = AstMetaKindEnd("End")
 	AstKindEnd         = AstMetaKindEnd("End")
 	AstKindError       = AstMetaKindError("Error")
 	AstKindError       = AstMetaKindError("Error")
@@ -65,8 +66,8 @@ func (astkind AstBasicMetaKind) String() string {
 	return string(astkind)
 	return string(astkind)
 }
 }
 
 
-func (astkind AstBasicMetaKind) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstBasicMetaKind) Run(vm *VM, ast Ast, val ListValue) Value {
+	return EmptyListValue()
 }
 }
 
 
 func (astkind AstMetaKindNone) String() string        { return "AstNone       " }
 func (astkind AstMetaKindNone) String() string        { return "AstNone       " }
@@ -94,71 +95,107 @@ func (astkind AstMetaKindError) String() string       { return "AstError      "
 func (astkind AstMetaKindFlatten) String() string     { return "AstFlatten    " }
 func (astkind AstMetaKindFlatten) String() string     { return "AstFlatten    " }
 
 
 
 
-func (astkind AstMetaKindNone) Run(vm *VM, ast Ast, val []Value) []Value { return EmptyValueArray() }
+func (astkind AstMetaKindNone) Run(vm *VM, ast Ast, val ListValue) Value {return EmptyListValue() }
 
 
-func (astkind AstMetaKindProgram) Run(vm *VM, ast Ast, val []Value) []Value {
-	res := EmptyValueArray()
+func (astkind AstMetaKindProgram) Run(vm *VM, ast Ast, val ListValue) Value {
+	res := EmptyListValue()
 	for _, child := range ast.Children() {
 	for _, child := range ast.Children() {
-		res = append(res, child.Run(vm, val)...)
+		res.Append(child.Run(vm, val))
 	}
 	}
 	return res
 	return res
 }
 }
 
 
-func (astkind AstMetaKindStatements) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindStatements) Run(vm *VM, ast Ast, val ListValue) Value {
+	res := EmptyListValue()
+	for _, child := range ast.Children() {
+		res.Append(child.Run(vm, val))
+	}
+	return res
+}
+
+func (astkind AstMetaKindStatement) Run(vm *VM, ast Ast, val ListValue) Value {
+	return vm.RunChildren(ast, val)
+}
+
+func (astkind AstMetaKindClosed) Run(vm *VM, ast Ast, val ListValue) Value {return EmptyListValue() }
+func (astkind AstMetaKindSet) Run(vm *VM, ast Ast, val ListValue) Value {
+	varName := ast.Value()
+	value := vm.RunChildren(ast, val)
+	vm.Register(varName.String(), value)
+	return value
+}
+
+func (astkind AstMetaKindGet) Run(vm *VM, ast Ast, val ListValue) Value {
+	varName := ast.Value()
+	return NewListValue(vm.Lookup(varName.String()))
 }
 }
-func (astkind AstMetaKindStatement) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+
+func (astkind AstMetaKindTarget) Run(vm *VM, ast Ast, val ListValue) Value {
+	return NewListValue(ast.Value())
 }
 }
-func (astkind AstMetaKindClosed) Run(vm *VM, ast Ast, val []Value) []Value { return EmptyValueArray() }
-func (astkind AstMetaKindSet) Run(vm *VM, ast Ast, val []Value) []Value { return EmptyValueArray() }
-func (astkind AstMetaKindGet) Run(vm *VM, ast Ast, val []Value) []Value { return EmptyValueArray() }
-func (astkind AstMetaKindTarget) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindCommand) Run(vm *VM, ast Ast, val ListValue) Value {
+	commandName := ast.Value()	
+	arglist, _ := vm.RunChildren(ast, val).(ListValue)
+	arguments := arglist.First()
+	log.Printf("Command execute: %s %v", commandName.String(), arguments)
+	return vm.CallNamed(commandName.String(), arguments)
 }
 }
-func (astkind AstMetaKindCommand) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindArguments) Run(vm *VM, ast Ast, val ListValue) Value {	
+	return vm.RunChildren(ast, val)
 }
 }
-func (astkind AstMetaKindArguments) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindArgument) Run(vm *VM, ast Ast, val ListValue) Value {
+	panic("AstMetaKindArgument")
+	vm.RunChildren(ast, val)
+	reslist, _ := vm.RunChildren(ast, val).(ListValue)
+	return reslist.First()
 }
 }
-func (astkind AstMetaKindArgument) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindExpression) Run(vm *VM, ast Ast, val ListValue) Value {
+	return vm.RunChildren(ast, val)
 }
 }
-func (astkind AstMetaKindExpression) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindBlock) Run(vm *VM, ast Ast, val ListValue) Value {
+	return vm.RunChildren(ast, val)
 }
 }
-func (astkind AstMetaKindBlock) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindParenthesis) Run(vm *VM, ast Ast, val ListValue) Value {
+	return vm.RunChildren(ast, val)
 }
 }
-func (astkind AstMetaKindParenthesis) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindList) Run(vm *VM, ast Ast, val ListValue) Value {
+	return vm.RunChildren(ast, val)
 }
 }
-func (astkind AstMetaKindList) Run(vm *VM, ast Ast, val []Value) []Value { return EmptyValueArray() }
-func (astkind AstMetaKindCapture) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+
+func (astkind AstMetaKindCapture) Run(vm *VM, ast Ast, val ListValue) Value {
+	return vm.RunChildren(ast, val)
 }
 }
-func (astkind AstMetaKindWordValue) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindWordValue) Run(vm *VM, ast Ast, val ListValue) Value {
+	return ast.Value()
 }
 }
-func (astkind AstMetaKindWord) Run(vm *VM, ast Ast, val []Value) []Value { return EmptyValueArray() }
-func (astkind AstMetaKindType) Run(vm *VM, ast Ast, val []Value) []Value { return EmptyValueArray() }
-func (astkind AstMetaKindValue) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+
+func (astkind AstMetaKindWord) Run(vm *VM, ast Ast, val ListValue) Value {
+	return ast.Value()
 }
 }
-func (astkind AstMetaKindEnd) Run(vm *VM, ast Ast, val []Value) []Value { return EmptyValueArray() }
-func (astkind AstMetaKindError) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindType) Run(vm *VM, ast Ast, val ListValue) Value {
+	return ast.Value()
 }
 }
-func (astkind AstMetaKindFlatten) Run(vm *VM, ast Ast, val []Value) []Value {
-	return EmptyValueArray()
+func (astkind AstMetaKindValue) Run(vm *VM, ast Ast, val ListValue) Value {
+	return ast.Value()
+}
+
+func (astkind AstMetaKindEnd) Run(vm *VM, ast Ast, val ListValue) Value {
+	return EmptyListValue() 
+}
+
+func (astkind AstMetaKindError) Run(vm *VM, ast Ast, val ListValue) Value {
+	return NewListValue(ast.Value())
+}
+
+func (astkind AstMetaKindFlatten) Run(vm *VM, ast Ast, val ListValue) Value {
+	return EmptyListValue()
 }
 }
 
 
 
 
 
 
 type AstKind interface {
 type AstKind interface {
 	String() string
 	String() string
-	Run(vm *VM, ast Ast, val []Value) []Value
+	Run(vm *VM, ast Ast, val ListValue) Value
 }
 }
 
 
 /*
 /*
@@ -230,6 +267,10 @@ type Ast struct {
 	token    Token
 	token    Token
 }
 }
 
 
+func (ast Ast) Value() Value {
+	return ast.token.Value
+}
+
 func NewAst(kind AstKind, parent *Ast, children []*Ast, token Token) *Ast {
 func NewAst(kind AstKind, parent *Ast, children []*Ast, token Token) *Ast {
 	ast := &Ast{AstKind: kind, parent: parent, token: token}
 	ast := &Ast{AstKind: kind, parent: parent, token: token}
     return ast.AppendChildren(children...)
     return ast.AppendChildren(children...)
@@ -299,7 +340,10 @@ func (ast Ast) Child(index int) *Ast {
 	return ast.children[index]
 	return ast.children[index]
 }
 }
 
 
-func (ast Ast) Run(vm *VM, val []Value) []Value {
+func (ast Ast) Run(vm *VM, val ListValue) Value {
+	if vm != nil && vm.Tracer != nil {
+		vm.Trace(*vm, ast, val)
+	}
 	return ast.AstKind.Run(vm, ast, val)
 	return ast.AstKind.Run(vm, ast, val)
 }
 }
 
 
@@ -332,6 +376,22 @@ func (ast Ast) Display() {
 	})
 	})
 }
 }
 
 
+func (ast Ast) Dump() string {
+	result := ""
+	ast.Walk(func(node *Ast) *Ast {
+		depth := node.Depth()
+		result += fmt.Sprintf("%s", strings.Repeat("--", depth))
+		if node != nil {
+			result += fmt.Sprintf("Ast: %s\n", node.String())
+		} else {
+			result += fmt.Sprintf("Ast: nil node\n")
+		}
+		return nil
+	})
+	return result
+}
+
+
 func (ast Ast) Depth() int {
 func (ast Ast) Depth() int {
 	var depth int = 0
 	var depth int = 0
 	parent := ast.Parent()
 	parent := ast.Parent()
@@ -377,6 +437,21 @@ func NewAstWithToken(astkind AstKind, token Token) *Ast {
 	return NewAst(astkind, nil, EmptyAstArray(), token)
 	return NewAst(astkind, nil, EmptyAstArray(), token)
 }
 }
 
 
+// If AST has errors, return it as a merged error, otherwise returns nil 
+func (ast *Ast) ToError() error {
+	errlist := ast.Errors()
+	if len(errlist) < 1 {
+		return nil
+	} 
+	sep := ""
+	res := ""
+	for _, err := range errlist {
+		res = fmt.Sprintf("%s%s%s", res, sep, err)
+		sep = "\n"
+	}
+	return fmt.Errorf("%s", res)
+}
+
 /*
 /*
 type AstProgram struct{ Ast }
 type AstProgram struct{ Ast }
 type AstStatements struct{ Ast }
 type AstStatements struct{ Ast }

+ 47 - 0
builtin.go

@@ -0,0 +1,47 @@
+package muesli
+
+import "fmt"
+
+
+func printf(vm *VM, args ...Value) ListValue {
+	var form string
+	var rest = args[1:len(args)]
+	resri := ListFromList(rest)
+	err := From(args[0], &form)
+	if err != nil {
+		fmt.Printf("Error: %s\n", err.Error())
+	} else {
+		fmt.Printf(form, resri...)
+	}
+	return NewListValue()
+}
+
+func println(vm *VM, args ...Value) ListValue {
+	var msg string
+	// resri := ListFromList(rest)
+	err := From(args[0], &msg)
+	if err != nil {
+		fmt.Printf("Error: %s\n", err.Error())
+	}
+	fmt.Println(msg)
+	return NewListValue()
+}
+
+func p(vm *VM, args ...Value) ListValue {
+	argi := ListFromList(args)
+	fmt.Println(argi...)
+	for _, arg := range args {
+		fmt.Printf("%v\n", arg)
+	}	
+	return NewListValue()
+}
+
+
+func (vm *VM) RegisterBuiltins() {
+	vm.RegisterBuiltin("p", p)
+	vm.RegisterBuiltin("prinln", println)
+	vm.RegisterBuiltin("printf", printf)
+}
+
+
+

+ 86 - 0
cmd/muesli/main.go

@@ -0,0 +1,86 @@
+package main
+
+import (
+	"log"
+	"os"
+	"path/filepath"
+)
+
+import "gitlab.com/beoran/muesli"
+import "github.com/peterh/liner"
+
+type LogTracer struct {
+}
+
+func (t * LogTracer) Trace(vm muesli.VM, ast muesli.Ast, val muesli.ListValue) bool {
+	log.Printf("Trace: %s %v", ast.String(), val)
+	return false
+}
+
+func runLine(vm *muesli.VM, in string) error {	
+	parser := muesli.NewParserFromString(in)
+	ast := parser.Parse()
+	err := ast.ToError()
+	if err != nil {
+		return err
+	}
+	vm.RunAst(*ast, muesli.NewListValue())
+	
+	return nil
+}
+
+func runLines(vm *muesli.VM, line *liner.State) error {
+	for { 	
+		if in, err := line.Prompt("> "); err == nil {
+			err = runLine(vm, in)
+			if err != nil { 
+				log.Print("Error %s: ", err)
+			}
+			line.AppendHistory(in)
+		} else if err == liner.ErrPromptAborted {
+			log.Print("Aborted")
+			return nil
+		} else {
+			log.Print("Error reading line: ", err)
+		}
+	}
+	return nil
+}
+
+func main() {
+	vm := muesli.NewVM()
+	vm.Tracer = &LogTracer{}
+	vm.RegisterBuiltins() 
+	line := liner.NewLiner()
+	defer line.Close()
+
+	line.SetCtrlCAborts(true)
+	home, _ := os.UserHomeDir()	
+	historyName := filepath.Join(home, ".muesli_history")
+
+	/* line.SetCompleter(func(line string) (c []string) {
+		for _, n := range names {
+			if strings.HasPrefix(n, strings.ToLower(line)) {
+				c = append(c, n)
+			}
+		}
+		return
+	})
+	*/
+
+	if f, err := os.Open(historyName); err == nil {
+		line.ReadHistory(f)
+		f.Close()
+	} 
+	
+	runLines(vm, line)
+	
+	if f, err := os.Create(historyName); err != nil {
+		log.Print("Error writing history file: ", err)
+	} else {
+		line.WriteHistory(f)
+		f.Close()
+	}
+}
+
+

+ 13 - 14
design_muesli.muesli

@@ -15,7 +15,7 @@
 but the {} pairs must match. 
 but the {} pairs must match. 
 }
 }
 
 
- 
+
 
 
 # Empty lines are ignored.
 # Empty lines are ignored.
 
 
@@ -48,11 +48,11 @@ p -7.000005
 # The [ ] must be space separated. 
 # The [ ] must be space separated. 
 # The type is Any[] if heterogenous,  
 # The type is Any[] if heterogenous,  
 
 
-# p [ foo "bar" ] 
+p [ foo "bar" ]
 
 
 # The type is Int[]  below
 # The type is Int[]  below
 
 
-# p [ 1 2 3 ] 
+p [ 1 2 3 ]
 
 
 
 
 # A sequence of a lower case letter followed by anything that is not whitespace.
 # A sequence of a lower case letter followed by anything that is not whitespace.
@@ -87,12 +87,12 @@ command {
     print "second block"
     print "second block"
 }
 }
 
 
-# In Muesli all values are typed. Types can be defined by the built type command.
+# In Muesli all values are typed. Types can be defined by the builtin type command.
 type Door ( object locked Bool keys Item[] )
 type Door ( object locked Bool keys Item[] )
 
 
 # Commands can be defined by the built in 'to' command. 
 # Commands can be defined by the built in 'to' command. 
 # They can have many arguments and many results.
 # They can have many arguments and many results.
-to open [door Door key Item]  Bool {
+to open[door Door key Item]  Bool {
     if (contains (member door key) key) {
     if (contains (member door key) key) {
         set (member door open) true
         set (member door open) true
     }
     }
@@ -109,8 +109,13 @@ to open [door Door key Item]  Bool {
 # and for primitive types <Bool|Int|String|Float|Word|Type>, Primitive, Any
 # and for primitive types <Bool|Int|String|Float|Word|Type>, Primitive, Any
 # You can override commands with more specific ones but not existing ones 
 # You can override commands with more specific ones but not existing ones 
 # that have the same specificity.
 # that have the same specificity.
-# Variables are nor part of the language but of the built in commands
-# Variables are set in the current scope with
+# To create such an overload you should create a "cover" with the builtin 
+# cover command. Covers are commands that dispatch to other commands based on 
+# the types of the arguments. 
+cover open open[door Door key Item]
+
+# Variables are not part of the language but there arebuiltin commands
+# to define them. Variables are set in the current scope with
 set a 10
 set a 10
 # And fetched in the current scope with get
 # And fetched in the current scope with get
 print (get a 10) 
 print (get a 10) 
@@ -121,7 +126,6 @@ upset a 10
 # =foo bar gets mapped to (set foo bar)
 # =foo bar gets mapped to (set foo bar)
 =a 10
 =a 10
 
 
-
 # $foo means (get foo)  
 # $foo means (get foo)  
 print $a
 print $a
 
 
@@ -135,8 +139,7 @@ print $a
 # Or indirect getters
 # Or indirect getters
 print $$indirect
 print $$indirect
 
 
-
-# Control structures are merely built in functions.
+# Control structures are merely builtin functions.
 
 
 if (less a 10) {
 if (less a 10) {
     print "Less"
     print "Less"
@@ -149,7 +152,6 @@ if (less a 10) {
 # embedded commands.
 # embedded commands.
 # Do note that MUESLI uses dynamic scoping for ease of implementation
 # Do note that MUESLI uses dynamic scoping for ease of implementation
 
 
-
 #{
 #{
 
 
 BLOCK
 BLOCK
@@ -166,8 +168,5 @@ PUSHW a
 CALL less
 CALL less
 CALL if
 CALL if
 
 
-
-
-
 }
 }
 
 

+ 3 - 1
go.mod

@@ -1,3 +1,5 @@
-module muesli
+module gitlab.com/beoran/muesli
 
 
 go 1.12
 go 1.12
+
+require github.com/peterh/liner v1.1.0

+ 4 - 0
go.sum

@@ -0,0 +1,4 @@
+github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
+github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/peterh/liner v1.1.0 h1:f+aAedNJA6uk7+6rXsYBnhdo4Xux7ESLe+kcuVUF5os=
+github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=

+ 38 - 27
parser.go

@@ -56,21 +56,25 @@ type Parser struct {
 type ParserError struct {
 type ParserError struct {
     *Parser
     *Parser
     *Token 
     *Token 
-    Error error
+    Chain error
+}
+
+func (pe ParserError) Error() string {
+	return fmt.Sprintf("%s %s", pe.Token.String(), pe.Chain.Error())
 }
 }
 
 
 func (parser *Parser) SetLogger(logger Logger) {
 func (parser *Parser) SetLogger(logger Logger) {
 	parser.LoggerWrapper = LoggerWrapper{logger}
 	parser.LoggerWrapper = LoggerWrapper{logger}
 }
 }
 
 
-func (parser *Parser) Errorf(message string, args ...string) ParserError {
-	err := fmt.Errorf(message+" at token "+parser.current.String(), args)
-    pe := ParserError { Parser: parser, Token:&parser.current, Error: err }
+func (parser *Parser) Errorf(message string, args ...interface{}) ParserError {
+	err := fmt.Errorf(message, args...)
+    pe := ParserError { Parser: parser, Token:&parser.current, Chain: err }
     parser.Errors = append(parser.Errors, pe)
     parser.Errors = append(parser.Errors, pe)
     return pe
     return pe
 }
 }
 
 
-func (parser *Parser) Panicf(message string, args ...string)  {
+func (parser *Parser) Panicf(message string, args ...interface{})  {
     pe := parser.Errorf(message, args...)
     pe := parser.Errorf(message, args...)
     panic(pe)
     panic(pe)
 }
 }
@@ -81,8 +85,8 @@ func (parser *Parser) Advance() {
 	parser.LogDebug("Next token: %s\n", token.String())
 	parser.LogDebug("Next token: %s\n", token.String())
 }
 }
 
 
-/* Skips tokens until a closer ) } ] OEX or EOF is found, to skip parse errors,
- * and to be able to continue parsing despite errors.. */
+/* Skips tokens until a closer, namely ), }, ], EOX or EOF is found, 
+ * to skip parse errors, and to be able to continue parsing despite errors. */
 func (parser *Parser) SkipError() Token {
 func (parser *Parser) SkipError() Token {
     parser.Advance()
     parser.Advance()
     for {
     for {
@@ -99,13 +103,15 @@ func (parser *Parser) SkipError() Token {
 
 
 /* Looks at the current token and advances the lexer if the token is of any of
 /* Looks at the current token and advances the lexer if the token is of any of
 the token kinds given in kinds. In this case it will return the accepted
 the token kinds given in kinds. In this case it will return the accepted
-token and advance the parser. Otherwise, it will call panicf with ann
-* "Suntax error unexpected <token>".*/
+token and advance the parser. Otherwise, it will call parser.Panicf with a
+* "Syntax error unexpected <token>".*/
 func (parser *Parser) Require(kinds ...TokenKind) Token {
 func (parser *Parser) Require(kinds ...TokenKind) Token {
 	if parser.current.IsNone() {
 	if parser.current.IsNone() {
 		parser.Advance()
 		parser.Advance()
 	}
 	}
-	    
+	
+	expected := ""
+	sep := ""    
 	for _, kind := range kinds {
 	for _, kind := range kinds {
 		if kind == parser.current.TokenKind {
 		if kind == parser.current.TokenKind {
 			accepted := parser.current
 			accepted := parser.current
@@ -113,8 +119,10 @@ func (parser *Parser) Require(kinds ...TokenKind) Token {
             parser.LogDebug("Require: Accepted token: %s\n", accepted.String())
             parser.LogDebug("Require: Accepted token: %s\n", accepted.String())
 			return accepted
 			return accepted
 		}
 		}
+		expected = fmt.Sprintf("%s%s%s", expected, sep, kind.String())
 	}
 	}
-	parser.Panicf("error: unexpected token %s", parser.current.String())
+	
+	parser.Panicf("error: expected one of the following: %s", expected)
 	return Token{}
 	return Token{}
 }
 }
 
 
@@ -123,6 +131,7 @@ func (parser *Parser) NewAstError(message string, args ...interface{}) *Ast {
 	sv := StringValue(fmt.Sprintf(message+" at token "+parser.current.String(), args))
 	sv := StringValue(fmt.Sprintf(message+" at token "+parser.current.String(), args))
 	pos := parser.current.Position
 	pos := parser.current.Position
 	tok := NewToken(TokenKindError, sv, pos)
 	tok := NewToken(TokenKindError, sv, pos)
+	parser.Errorf(message, args...)
 	return NewAst(AstKindError, nil, EmptyAstArray(), tok)
 	return NewAst(AstKindError, nil, EmptyAstArray(), tok)
 }
 }
 
 
@@ -163,7 +172,7 @@ func (parser *Parser) ParseArgument() *Ast {
 			case parser.NextIsSet(): return parser.ParseSet()
 			case parser.NextIsSet(): return parser.ParseSet()
 			case parser.NextIsClosed(): return parser.ParseClosed()
 			case parser.NextIsClosed(): return parser.ParseClosed()
 			case parser.NextIsWordValue(): return parser.ParseWordValue()
 			case parser.NextIsWordValue(): return parser.ParseWordValue()
-			default: parser.Panicf("error: in argument: unexpected %s", parser.current.String())
+			default: parser.Panicf("error: in argument: expected $, =, }, word or value")
 			return nil
 			return nil
 	}
 	}
 }
 }
@@ -270,7 +279,7 @@ func (parser *Parser) ParseTarget() *Ast {
 			target = NewAstWithToken(AstKindTarget, parser.current)
 			target = NewAstWithToken(AstKindTarget, parser.current)
 			target.AppendChild(parser.ParseClosed())
 			target.AppendChild(parser.ParseClosed())
 		default: 
 		default: 
-			parser.Panicf("Malformed setter: %s", parser.current.String())
+			parser.Panicf("Malformed setter.")
 			return nil
 			return nil
 	} 	
 	} 	
 	
 	
@@ -302,7 +311,7 @@ func (parser *Parser) ParseOrigin() *Ast {
 			target = NewAstWithToken(AstKindTarget, parser.current)
 			target = NewAstWithToken(AstKindTarget, parser.current)
 			target.AppendChild(parser.ParseClosed())
 			target.AppendChild(parser.ParseClosed())
 		default: 
 		default: 
-			parser.Panicf("Malformed getter: %s", parser.current.String())
+			parser.Panicf("Malformed getter")
 			return nil
 			return nil
 	} 	
 	} 	
 	
 	
@@ -347,7 +356,7 @@ func (parser *Parser) ParseClosed() *Ast {
 		case parser.NextIs(TokenKindOpenParen): return parser.ParseParenthesis()
 		case parser.NextIs(TokenKindOpenParen): return parser.ParseParenthesis()
 		case parser.NextIs(TokenKindOpenList): return parser.ParseList()
 		case parser.NextIs(TokenKindOpenList): return parser.ParseList()
 		default:
 		default:
-			parser.Panicf("Syntax error in closed, unexpected: %s", parser.current.String())
+			parser.Panicf("Syntax error in closed, expected {, (, [")
 			return nil
 			return nil
 	}
 	}
 }
 }
@@ -361,7 +370,7 @@ func (parser *Parser) ParseExpression() *Ast {
 		case parser.NextIsGet(): return parser.ParseGet()
 		case parser.NextIsGet(): return parser.ParseGet()
 		case parser.NextIsValue(): return parser.ParseValue()
 		case parser.NextIsValue(): return parser.ParseValue()
 		default: 
 		default: 
-			parser.Panicf("Syntax error in expression, unexpected: %s", parser.current.String())
+			parser.Panicf("Syntax error in expression, expected word, $, =, value")
 			return nil
 			return nil
     }
     }
 }
 }
@@ -373,8 +382,8 @@ func (parser *Parser) ParseExpressionStatement() *Ast {
         return NewAstNone()
         return NewAstNone()
     }
     }
     
     
-    // Expression statements must end on EOX
-    if eox := parser.Require(TokenKindEOX); eox.IsError() {
+    // Expression statements must end on EOX or EOF
+    if eox := parser.Require(TokenKindEOX, TokenKindEOF); eox.IsError() {
 		return parser.NewAstError("expected end of statement")
 		return parser.NewAstError("expected end of statement")
 	}
 	}
     
     
@@ -384,7 +393,7 @@ func (parser *Parser) ParseExpressionStatement() *Ast {
 
 
 func (parser *Parser) ParseEmptyStatement() *Ast {
 func (parser *Parser) ParseEmptyStatement() *Ast {
     parser.LogDebug("ParseEmptyStatement: %s\n", parser.current.String())
     parser.LogDebug("ParseEmptyStatement: %s\n", parser.current.String())
-	if eox := parser.Require(TokenKindEOX); eox.IsError() {
+	if eox := parser.Require(TokenKindEOX, TokenKindEOF); eox.IsError() {
 		return parser.NewAstError("expected end of statement")
 		return parser.NewAstError("expected end of statement")
 	}
 	}
     return NewAstWithToken(AstKindStatement, parser.current)
     return NewAstWithToken(AstKindStatement, parser.current)
@@ -442,7 +451,6 @@ func (parser Parser) NextIsErrorSkipped() bool {
     TokenKindEOX, TokenKindEOF)
     TokenKindEOX, TokenKindEOF)
 }
 }
 
 
-
 func (parser Parser) NextIsEOX() bool {
 func (parser Parser) NextIsEOX() bool {
     return parser.NextIs(TokenKindEOX)
     return parser.NextIs(TokenKindEOX)
 }
 }
@@ -451,7 +459,6 @@ func (parser Parser) NextIsEOF() bool {
     return parser.NextIs(TokenKindEOF)
     return parser.NextIs(TokenKindEOF)
 }
 }
 
 
-
 func (parser Parser) NextIsExpression() bool {
 func (parser Parser) NextIsExpression() bool {
     return parser.NextIs(TokenKindWord,
     return parser.NextIs(TokenKindWord,
                     TokenKindGet,
                     TokenKindGet,
@@ -476,8 +483,8 @@ func (parser *Parser) ParseStatement() *Ast {
         case parser.NextIsExpression(): return parser.ParseExpressionStatement()
         case parser.NextIsExpression(): return parser.ParseExpressionStatement()
         case parser.NextIsEOX(): return parser.ParseEmptyStatement()
         case parser.NextIsEOX(): return parser.ParseEmptyStatement()
         default:
         default:
-        parser.Panicf("Unexpected token in statement")
-        return parser.NewAstError("Unexpected token in statement")
+        parser.Panicf("Expected closed, expression, or EOX in statement")
+        return parser.NewAstError("Expected closed, expression, or EOX in statement")
     }
     }
 }
 }
 
 
@@ -509,14 +516,18 @@ func (parser *Parser) ParseProgram() *Ast {
 	return NewAst(AstKindProgram, nil, children, NoToken())
 	return NewAst(AstKindProgram, nil, children, NoToken())
 }
 }
 
 
-func (parser *Parser) Parse() *Ast {
-	defer func() {		
+func (parser *Parser) Parse() (ast *Ast) {
+	defer func() {
 		if err := recover() ; err != nil {
 		if err := recover() ; err != nil {
-			fmt.Printf("Parse error, recovered: %s %s\n", err, parser.current.String())
+			if perr, ok := err.(ParserError) ; ok{ 
+				ast = parser.NewAstError("Parse error, recovered: %s\n", perr)
+			} else {
+				panic(err)
+			}
 		}
 		}
 	} ()
 	} ()
 	parser.Advance()
 	parser.Advance()
-	ast := parser.ParseProgram()
+	ast = parser.ParseProgram()
 	return ast
 	return ast
 }
 }
 
 

+ 6 - 5
parser_test.go

@@ -11,7 +11,7 @@ func HelperFailOnErrors(ast * Ast, expected int, test *testing.T) {
 		return
 		return
 	}	
 	}	
 	if ast.IsNone() {
 	if ast.IsNone() {
-		test.Errorf("Parse failed, %d parse errors expected", expected)
+		test.Logf("Parse failed, %d parse errors expected", expected)
 	}
 	}
 	errors := ast.Errors()
 	errors := ast.Errors()
 	if len(errors) != expected {
 	if len(errors) != expected {
@@ -25,12 +25,13 @@ func HelperFailOnErrors(ast * Ast, expected int, test *testing.T) {
 
 
 func HelperParseAndFailOnErrors(prog string, expected int,
 func HelperParseAndFailOnErrors(prog string, expected int,
 	parsefunc func(*Parser) *Ast, test *testing.T) {
 	parsefunc func(*Parser) *Ast, test *testing.T) {
-		defer func(){
+	/*	defer func(){
 			err := recover()
 			err := recover()
 			if err != nil {
 			if err != nil {
 				test.Errorf("Parse error: %s", err)
 				test.Errorf("Parse error: %s", err)
 			}
 			}
 		}()
 		}()
+	*/
 	
 	
 	parser := NewParserFromString(prog)
 	parser := NewParserFromString(prog)
 	parser.SetLogger(&testLogger{"", 0, test})
 	parser.SetLogger(&testLogger{"", 0, test})
@@ -38,11 +39,11 @@ func HelperParseAndFailOnErrors(prog string, expected int,
 	HelperFailOnErrors(ast, expected, test)
 	HelperFailOnErrors(ast, expected, test)
 	if ast != nil { 
 	if ast != nil { 
 		test.Logf("AST OK")
 		test.Logf("AST OK")
-		// ast.Display()
+		test.Logf("\nAst: %s\n",  ast.Dump())		
 	}
 	}
 }
 }
 
 
-func TestParser(test *testing.T) {
+func TestParser1(test *testing.T) {
 	com := `puts "hello" 
 	com := `puts "hello" 
 	say ( add 5 10 ) .`
 	say ( add 5 10 ) .`
 	parser := NewParserFromString(com)
 	parser := NewParserFromString(com)
@@ -89,7 +90,7 @@ func TestParseDesignFile(test *testing.T) {
     ast := parser.Parse()
     ast := parser.Parse()
     if ast != nil { 
     if ast != nil { 
 		test.Logf("Ast OK.")
 		test.Logf("Ast OK.")
-		// ast.Display()
+		test.Logf("\nAst: %s\n",  ast.Dump())
 	}
 	}
     
     
 }
 }

+ 6 - 3
token.go

@@ -11,6 +11,10 @@ type Position struct {
 	Column   int
 	Column   int
 }
 }
 
 
+func (p Position) String() string {
+	return fmt.Sprintf("%s:%d:%d", p.FileName, p.Line, p.Column)
+}
+
 /* Token Kind. Uses a rune to easily handle single character tokens. */
 /* Token Kind. Uses a rune to easily handle single character tokens. */
 type TokenKind rune
 type TokenKind rune
 
 
@@ -78,11 +82,10 @@ type Token struct {
 
 
 func (token Token) String() string {
 func (token Token) String() string {
 	if token.Value == nil {
 	if token.Value == nil {
-		return fmt.Sprintf("<%s:nil:%v>", token.TokenKind.String(), token.Position)
+		return fmt.Sprintf("%s:%s:nil", token.Position.String(), token.TokenKind.String())
 
 
 	}
 	}
-	return fmt.Sprintf("<%s:%q:%v>", token.TokenKind.String(),
-		token.Value.String(), token.Position)
+	return fmt.Sprintf("%s:%s:%v", token.Position.String(), token.TokenKind.String(), token.Value)
 }
 }
 
 
 func (token Token) Error() string {
 func (token Token) Error() string {

+ 19 - 0
value.go

@@ -14,11 +14,14 @@ type StringValue string
 type BoolValue bool
 type BoolValue bool
 type WordValue string
 type WordValue string
 type TypeValue string
 type TypeValue string
+
 type ErrorValue struct {
 type ErrorValue struct {
 	error
 	error
 }
 }
+
 type EmptyValue struct {
 type EmptyValue struct {
 }
 }
+
 type ListValue struct {
 type ListValue struct {
 	List []Value
 	List []Value
 }
 }
@@ -113,6 +116,22 @@ func (list *ListValue) Append(elements ...Value) {
 	list.List = append(list.List, elements...)
 	list.List = append(list.List, elements...)
 }
 }
 
 
+func (list *ListValue) AppendList(toAppend ListValue) {
+	list.List = append(list.List, toAppend.List...)
+}
+
+func (list *ListValue) Index(i int) Value {
+	if i >= len(list.List) {
+		return NilValue
+	}
+	return list.List[i]
+}
+
+
+func (list *ListValue) First() Value {
+	return list.Index(0)
+}
+
 func EmptyListValue() ListValue {
 func EmptyListValue() ListValue {
 	return ListValue{make([]Value, 0)}
 	return ListValue{make([]Value, 0)}
 }
 }

+ 48 - 14
vm.go

@@ -4,15 +4,15 @@ package muesli
 // import "fmt"
 // import "fmt"
 
 
 // Handler function
 // Handler function
-type Handler func(vm *VM, arguments ...Value) []Value
+type Handler func(vm *VM, arguments ...Value) ListValue
 
 
-func (handler *Handler) Call(vm *VM, arguments ...Value) []Value {
+func (handler *Handler) Call(vm *VM, arguments ...Value) ListValue {
 	return (*handler)(vm, arguments...)
 	return (*handler)(vm, arguments...)
 }
 }
 
 
 // A callable Value must implement the Caller interface
 // A callable Value must implement the Caller interface
 type Caller interface {
 type Caller interface {
-	Call(vm *VM, arguments ...Value) []Value
+	Call(vm *VM, arguments ...Value) ListValue
 }
 }
 
 
 // Callable value types
 // Callable value types
@@ -45,7 +45,7 @@ func NewBuiltinValue(name string, handler Handler) BuiltinValue {
 	return result
 	return result
 }
 }
 
 
-func (builtin *BuiltinValue) Call(vm *VM, arguments ...Value) []Value {
+func (builtin *BuiltinValue) Call(vm *VM, arguments ...Value) Value {
 	return vm.CallBuiltin(builtin.Handler, arguments...)
 	return vm.CallBuiltin(builtin.Handler, arguments...)
 }
 }
 
 
@@ -62,7 +62,7 @@ func NewDefinedValue(name string, definition *Ast) DefinedValue {
 	return result
 	return result
 }
 }
 
 
-func (defined *DefinedValue) Call(vm *VM, arguments ...Value) []Value {
+func (defined *DefinedValue) Call(vm *VM, arguments ...Value) Value {
 	return vm.CallDefined(defined.Definition, arguments...)
 	return vm.CallDefined(defined.Definition, arguments...)
 }
 }
 
 
@@ -115,6 +115,13 @@ type CoverValue struct {
 	Overloads map[Signature]Overload
 	Overloads map[Signature]Overload
 }
 }
 
 
+func NewCoverValue(name string) CoverValue {
+	result := CoverValue{}
+	result.Name = name
+	result.Overloads = make(map[Signature]Overload)
+	return result
+}
+
 func (cover *CoverValue) Call(vm *VM, arguments ...Value) ListValue {
 func (cover *CoverValue) Call(vm *VM, arguments ...Value) ListValue {
 	signature := CalculateSignature(arguments...)
 	signature := CalculateSignature(arguments...)
 	if overload, ok := cover.Overloads[signature]; ok {
 	if overload, ok := cover.Overloads[signature]; ok {
@@ -191,16 +198,21 @@ func NewFrame(parent *Frame) *Frame {
 	return &Frame{parent, EmptyValueArray(), EmptyValueArray(), false}
 	return &Frame{parent, EmptyValueArray(), EmptyValueArray(), false}
 }
 }
 
 
+type Tracer interface {
+	Trace(vm VM, ast Ast, val ListValue) bool
+}
+
 // Virtual machine
 // Virtual machine
 type VM struct {
 type VM struct {
 	TopScope *Scope // Top level scope
 	TopScope *Scope // Top level scope
 	TopFrame *Frame // Top level scope
 	TopFrame *Frame // Top level scope
 	*Scope          // Current Scope
 	*Scope          // Current Scope
 	*Frame          // Current frame
 	*Frame          // Current frame
+	Tracer			// Tracer to emit tracing info to, could be used for logging or debugging
 }
 }
 
 
 func NewVM() *VM {
 func NewVM() *VM {
-	vm := &VM{NewScope(nil), NewFrame(nil), nil, nil}
+	vm := &VM{NewScope(nil), NewFrame(nil), nil, nil, nil}
 	vm.Scope = vm.TopScope
 	vm.Scope = vm.TopScope
 	vm.Frame = vm.TopFrame
 	vm.Frame = vm.TopFrame
 	return vm
 	return vm
@@ -236,23 +248,31 @@ func (vm *VM) PopScope() *Scope {
 	return nil
 	return nil
 }
 }
 
 
-func (vm *VM) CallDefined(ast *Ast, arguments ...Value) []Value {
-	return ast.Run(vm, arguments)
+func (vm *VM) CallDefined(ast *Ast, arguments ...Value) Value {
+	arr := ast.Run(vm, NewListValue(arguments...))
+	return arr
 }
 }
 
 
-func (vm *VM) CallBuiltin(handler Handler, arguments ...Value) []Value {
+func (vm *VM) CallBuiltin(handler Handler, arguments ...Value) Value {
 	return handler.Call(vm, arguments...)
 	return handler.Call(vm, arguments...)
 }
 }
 
 
-func (vm *VM) CallNamed(name string, arguments ...Value) []Value {
+func (vm *VM) CallCover(cover CoverValue, arguments ...Value) Value {
+	return cover.Call(vm, arguments...)
+}
+
+
+func (vm *VM) CallNamed(name string, arguments ...Value) Value {
 	value := vm.Lookup(name)
 	value := vm.Lookup(name)
 	switch toCall := value.(type) {
 	switch toCall := value.(type) {
 	case BuiltinValue:
 	case BuiltinValue:
 		return vm.CallBuiltin(toCall.Handler, arguments...)
 		return vm.CallBuiltin(toCall.Handler, arguments...)
 	case DefinedValue:
 	case DefinedValue:
 		return vm.CallDefined(toCall.Definition, arguments...)
 		return vm.CallDefined(toCall.Definition, arguments...)
+	case CoverValue:
+		return vm.CallCover(toCall, arguments...)
 	default:
 	default:
-		return NewValueArray(NewErrorValuef("Cannot call %s: %v", name, value))
+		return NewListValue(NewErrorValuef("Cannot call %s: %v", name, value))
 	}
 	}
 }
 }
 
 
@@ -267,6 +287,11 @@ func (vm *VM) Register(name string, value Value) Value {
 	return vm.Scope.Register(name, value)
 	return vm.Scope.Register(name, value)
 }
 }
 
 
+func (vm *VM) RegisterCover(name string) Value {
+	value := NewCoverValue(name)
+	return vm.Register(name, value)
+}
+
 func (vm *VM) RegisterBuiltin(name string, handler Handler) Value {
 func (vm *VM) RegisterBuiltin(name string, handler Handler) Value {
 	value := NewBuiltinValue(name, handler)
 	value := NewBuiltinValue(name, handler)
 	return vm.Register(name, value)
 	return vm.Register(name, value)
@@ -281,15 +306,24 @@ func (vm *VM) Fail() {
 	vm.Frame.failed = true
 	vm.Frame.failed = true
 }
 }
 
 
-func (vm *VM) RunChildren(ast Ast, args ...Value) []Value {
-	result := NewValueArray()
+func (vm *VM) RunChildren(ast Ast, args ListValue) Value {
+	result := NewListValue()
 	for _, child := range ast.Children() {
 	for _, child := range ast.Children() {
 		val := child.Run(vm, args)
 		val := child.Run(vm, args)
-		result = append(result, val...)
+		reslist, isList := val.(ListValue)
+		if isList {
+			result.AppendList(reslist)
+		}
+		result.Append(val)
 	}
 	}
 	return result
 	return result
 }
 }
 
 
+func (vm *VM) RunAst(ast Ast, args ListValue) Value {
+	return ast.Run(vm, args)
+}
+
+
 /*
 /*
 
 
 func (vm *VM) RunProgram(ast *BasicAst) ListValue {
 func (vm *VM) RunProgram(ast *BasicAst) ListValue {

+ 12 - 10
vm_test.go

@@ -7,9 +7,9 @@ import (
 
 
 func TestVm1(test *testing.T) {
 func TestVm1(test *testing.T) {
 	vm := NewVM()
 	vm := NewVM()
-	bi := vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) []Value {
+	bi := vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) ListValue {
 		fmt.Printf("I am foo. See me foo?")
 		fmt.Printf("I am foo. See me foo?")
-		return EmptyValueArray()
+		return NewListValue()
 	})
 	})
 
 
 	if vm == nil {
 	if vm == nil {
@@ -32,9 +32,9 @@ func TestVm1(test *testing.T) {
 
 
 func ExampleVm1() {
 func ExampleVm1() {
 	vm := NewVM()
 	vm := NewVM()
-	vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) []Value {
+	vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) ListValue {
 		fmt.Printf("I am foo. See me foo?")
 		fmt.Printf("I am foo. See me foo?")
-		return EmptyValueArray()
+		return NewListValue()
 	})
 	})
 
 
 	foo := vm.Lookup("foo")
 	foo := vm.Lookup("foo")
@@ -50,11 +50,11 @@ func ExampleVm1() {
 
 
 func ExampleVm2() {
 func ExampleVm2() {
 	vm := NewVM()
 	vm := NewVM()
-	vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) []Value {
+	vm.RegisterBuiltin("foo", func(vm *VM, args ...Value) ListValue {
 		var s string
 		var s string
 		From(args[0], &s)
 		From(args[0], &s)
 		fmt.Printf("I am foo. See me %s?", s)
 		fmt.Printf("I am foo. See me %s?", s)
-		return EmptyValueArray()
+		return NewListValue()
 	})
 	})
 
 
 	//Output: I am foo. See me bar?
 	//Output: I am foo. See me bar?
@@ -64,7 +64,7 @@ func ExampleVm2() {
 
 
 func ExampleVm3() {
 func ExampleVm3() {
 	vm := NewVM()
 	vm := NewVM()
-	vm.RegisterBuiltin("multi", func(vm *VM, args ...Value) []Value {
+	vm.RegisterBuiltin("multi", func(vm *VM, args ...Value) ListValue {
 		var one string
 		var one string
 		var two int64
 		var two int64
 		err := ListFrom(args, &one, &two)
 		err := ListFrom(args, &one, &two)
@@ -72,7 +72,7 @@ func ExampleVm3() {
 			fmt.Printf("Error: %s", err.Error())
 			fmt.Printf("Error: %s", err.Error())
 		}
 		}
 		fmt.Printf("I am multi. See me %s, %d?", one, two)
 		fmt.Printf("I am multi. See me %s, %d?", one, two)
-		return EmptyValueArray()
+		return NewListValue()
 	})
 	})
 
 
 	//Output: I am multi. See me bar, 7?
 	//Output: I am multi. See me bar, 7?
@@ -82,7 +82,7 @@ func ExampleVm3() {
 
 
 func ExampleVm4() {
 func ExampleVm4() {
 	vm := NewVM()
 	vm := NewVM()
-	vm.RegisterBuiltin("printf", func(vm *VM, args ...Value) []Value {
+	vm.RegisterBuiltin("printf", func(vm *VM, args ...Value) ListValue {
 		var form string
 		var form string
 		var rest = args[1:len(args)]
 		var rest = args[1:len(args)]
 		resri := ListFromList(rest)
 		resri := ListFromList(rest)
@@ -92,10 +92,12 @@ func ExampleVm4() {
 		} else {
 		} else {
 			fmt.Printf(form, resri...)
 			fmt.Printf(form, resri...)
 		}
 		}
-		return EmptyValueArray()
+		return NewListValue()
 	})
 	})
 
 
 	//Output: printf 7
 	//Output: printf 7
 	vm.CallNamed("printf", ListTo("printf %d", 7)...)
 	vm.CallNamed("printf", ListTo("printf %d", 7)...)
 
 
 }
 }
+
+