Browse Source

A few things work better now

Beoran 4 years ago
parent
commit
b19c0c32ae
9 changed files with 447 additions and 48 deletions
  1. 45 11
      ast.go
  2. 155 3
      builtin.go
  3. 30 4
      cmd/muesli/main.go
  4. 27 5
      lexer.go
  5. 20 4
      parser.go
  6. 4 0
      test/testdata/test_0001.muesli
  7. 11 0
      test/testdata/test_0002.muesli
  8. 22 7
      value.go
  9. 133 14
      vm.go

+ 45 - 11
ast.go

@@ -4,7 +4,6 @@ package muesli
 import (
 	"fmt"
 	"strings"
-	"log"
 )
 
 type AstBasicMetaKind string
@@ -54,7 +53,7 @@ const (
 	// AstKindCapture     = AstMetaKindCapture("Capture")
 	AstKindWordValue   = AstMetaKindWordValue("WordValue")
 	AstKindWord        = AstMetaKindWord("Word")
-	// AstKindType        = AstMetaKindType("Type")
+	AstKindType        = AstMetaKindType("Type")
 	AstKindValue       = AstMetaKindValue("Value")
 	AstKindEnd         = AstMetaKindEnd("End")
 	AstKindError       = AstMetaKindError("Error")
@@ -106,7 +105,6 @@ func (astkind AstMetaKindStatements) Run(vm *VM, ast Ast, val ...Value) []Value
 }
 
 func (astkind AstMetaKindStatement) Run(vm *VM, ast Ast, val ...Value) []Value {
-	panic("AstMetaKindStatement")
 	return vm.RunChildren(ast, val...)
 }
 
@@ -116,15 +114,31 @@ func (astkind AstMetaKindSet) Run(vm *VM, ast Ast, val ...Value) []Value {
 	if len(values) < 2 { 
 		return Fail(fmt.Errorf("set needs at least 2 arguments: received %v", values)) 
 	}
-	log.Printf("(astkind AstMetaKindSet) Run: %v %v", values[0].String(), values[1])
-	vm.Register(values[0].String(), values[1])
-	return Ok(values[1])
+	target := values[0].String() 
+	value := values[1]
+	if target == "(" || target == "$" {
+		if len(values) < 3 {
+			return Fail(fmt.Errorf("indirect get needs results: received %v", values)) 
+		}
+		target = values[1].String() 
+		value = values[2]
+	}
+	// log.Printf("(astkind AstMetaKindSet) Run: %v %v", target, value)
+	vm.Register(target, value)
+	return Ok(value)
 }
 
 func (astkind AstMetaKindGet) Run(vm *VM, ast Ast, val ...Value) []Value {
-	target := vm.RunChildrenFirstResult(ast, val...)
-	log.Printf("(astkind AstMetaKindGet) Run: target %v", target)
-	return []Value{vm.Lookup(target.String())}
+	targets := vm.RunChildren(ast, val...)
+	target := targets[0].String() 
+	if target == "(" || target == "$" {
+		if len(targets) < 2 {
+			return Fail(fmt.Errorf("indirect get needs results: received %v", targets)) 
+		}
+		target = targets[1].String()
+	}
+	// log.Printf("(astkind AstMetaKindGet) Run: target %s", target)
+	return Ok(vm.Lookup(target))
 }
 
 func (astkind AstMetaKindTarget) Run(vm *VM, ast Ast, val ...Value) []Value {
@@ -136,7 +150,7 @@ func (astkind AstMetaKindTarget) Run(vm *VM, ast Ast, val ...Value) []Value {
 func (astkind AstMetaKindCommand) Run(vm *VM, ast Ast, val ...Value) []Value {
 	commandName := ast.Value()	
 	arguments := vm.RunChildren(ast, val...)
-	log.Printf("Command execute: %s %v", commandName.String(), arguments)
+	// log.Printf("Command execute: %s %v", commandName.String(), arguments)
 	return vm.CallNamed(commandName.String(), arguments...)
 }
 
@@ -155,7 +169,9 @@ func (astkind AstMetaKindExpression) Run(vm *VM, ast Ast, val ...Value) []Value
 }
 
 func (astkind AstMetaKindBlock) Run(vm *VM, ast Ast, val ...Value) []Value {
-	return []Value{vm.RunChildrenLastResult(ast, val...)}
+	// A block is not executed. It results in an anonymous runnable.
+	ast.Display()
+	return Ok(NewBlockValue(&ast))
 }
 
 func (astkind AstMetaKindParenthesis) Run(vm *VM, ast Ast, val ...Value) []Value {
@@ -460,6 +476,24 @@ func (ast *Ast) ToError() error {
 	return fmt.Errorf("%s", res)
 }
 
+func (from Ast) Convert(to interface{}) error {
+	switch toPtr := to.(type) {
+		case *Ast:
+			(*toPtr) = from
+		default:
+			return NewErrorValuef("Cannot convert Ast value %v to %v", from, to)
+	}
+	return nil
+}
+
+const TypeValueAst = TypeValue("Ast")
+
+func (ast Ast) Type() TypeValue {
+	return TypeValueAst
+}
+
+
+
 /*
 type AstProgram struct{ Ast }
 type AstStatements struct{ Ast }

+ 155 - 3
builtin.go

@@ -2,6 +2,7 @@ package muesli
 
 import "fmt"
 import "log"
+import "runtime"
 
 type LogTracer struct {
 }
@@ -32,7 +33,8 @@ func printf(vm *VM, args ...Value) []Value {
 	if err != nil {
 		return Fail(err)
 	}
-	fmt.Printf(format, rest...)
+	extra := ListFromList(rest)
+	fmt.Printf(format, extra...)
 	return None()
 }
 
@@ -182,10 +184,153 @@ func val(vm *VM, args ...Value) []Value {
 	return args
 }
 
+func to(vm *VM, args ...Value) []Value {
+	var name string	
+	rest, err := ParseArgs(args, &name)
+	if err != nil {
+		return Fail(err)
+	}
+	
+	if len(rest) < 1 {
+		return Fail(NewErrorValuef("Need at least 2 arguments: %v", args))
+	}
+	
+	last := rest[len(rest)-1]
+	block, isBlock := last.(*BlockValue)
+	if ! isBlock {
+		return Fail(NewErrorValuef("Not a block: %v", last))
+	}
+	param := rest[0:len(rest)-1]
+	defpars := []*Parameter{}
+	for i := 1 ; i < len(param) ; i += 2 {
+		par := &Parameter{}
+		name := param[i-1]
+		typ  := param[i]
+		var ok bool
+		if par.Name, ok = name.(WordValue); !ok {
+			return Fail(NewErrorValuef("Not a word value: %v", name))
+		}
+		if par.Type, ok = typ.(TypeValue); !ok {
+			return Fail(NewErrorValuef("Not a type value: %v", typ))
+		}
+		defpars = append(defpars, par) 
+	}
+	
+	return Ok(vm.RegisterDefined(name, defpars, block))
+}
+
+func cover(vm *VM, args ...Value) []Value {
+	var name, target string
+	rest, err := ParseArgs(args, &name, &target)
+	if err != nil {
+		return Fail(err)
+	}
+	types := []TypeValue{}
+	for i, arg := range rest {
+		if typ, ok := arg.(TypeValue) ; ok {
+			types = append(types, typ)
+		} else {
+			return Fail(NewErrorValuef("Argument %d: not a type: %v %s", i+2, arg, arg.String()))
+		}
+	}	
+	err = vm.AddOverload(name, target, types...)
+	
+	if err != nil {
+		return Fail(err)
+	}	
+	return Ok()
+}
+
+func types(vm *VM, args ...Value) []Value {
+	result := []Value{}
+	for i, arg := range args {
+		typ := arg.Type() 
+		result = append(result, typ)
+		fmt.Printf("Type %d: %s\n", i, typ.String())
+	}
+	return Ok(NewListValue(result...))
+}
+
+func set(vm *VM, val ...Value) []Value {
+	if len(val) < 2 { 
+		return Fail(fmt.Errorf("set needs at least 2 arguments: received %v", val)) 
+	}
+	target := val[0].String() 
+	value := val[1]
+	if target == "(" || target == "$" {
+		if len(val) < 3 {
+			return Fail(fmt.Errorf("indirect get needs results: received %v", val)) 
+		}
+		target = val[1].String() 
+		value = val[2]
+	}	
+	vm.Register(target, value)
+	return Ok(value)
+}
+
+func get(vm *VM, val ...Value) []Value {
+	if len(val) < 1 {
+		return Fail(fmt.Errorf("get needs at least 1 argument")) 
+	}
+	target := val[0].String() 
+	if target == "(" || target == "$" {
+		if len(val) < 2 {
+			return Fail(fmt.Errorf("indirect get needs results: received %v", val)) 
+		}
+		target = val[1].String()
+	}	
+	return Ok(vm.Lookup(target))
+}
+
+func help(vm *VM, val ...Value) [] Value {
+	if len(val) < 1 {
+		fmt.Printf("help <callable> will display help on the callable\n")
+		return Ok()
+	}
+	targetName := val[0].String() 	
+	target := vm.Lookup(targetName)
+	if target == nil {
+		fmt.Printf("help: %s not found.\n", targetName)
+	}
+	
+	if helper, isHelper := target.(Helper) ; isHelper {
+		help := helper.Help()
+		fmt.Printf("%s: %s.\n", targetName, help)
+		return Ok(StringValue(help))
+	}
+	
+	return Ok()
+}
+
+func explain(vm *VM, val ...Value) [] Value {
+	var target, help string
+	_, err := ParseArgs(val, &target, &help)
+	if err != nil {
+		return Fail(err)
+	}	
+	err = vm.SetHelp(target, help)
+	if err != nil {
+		return Fail(err)
+	}		
+	return Ok(StringValue(help))
+}
+
+func exit(vm *VM, val ...Value) [] Value {
+	var code int
+	_, err := ParseArgs(val, &code)
+	if err != nil {
+		runtime.Goexit()
+	}	
+	vm.ExitStatus = code
+	runtime.Goexit()
+	return Ok()
+}
+
 
 func (vm *VM) RegisterBuiltins() {
-	vm.RegisterBuiltin("addi", addi)
-	vm.RegisterBuiltin("addf", addf)
+	vm.RegisterBuiltinWithHelp("addi", addi, `[Int Int] -> Int: adds two integers together`)
+	vm.RegisterBuiltinWithHelp("addf", addf, `[Int Int] -> Int: adds two floats together`)
+	vm.RegisterBuiltin("cover", cover)
 	vm.RegisterBuiltin("sumi", sumi)
 	vm.RegisterBuiltin("sumf", sumf)
 	vm.RegisterBuiltin("subi", subi)
@@ -216,7 +361,14 @@ func (vm *VM) RegisterBuiltins() {
 	vm.RegisterBuiltin("println", println)
 	vm.RegisterBuiltin("printf", printf)
 	vm.RegisterBuiltin("trace", trace)
+	vm.RegisterBuiltin("to", to)
+	vm.RegisterBuiltin("types", types)
 	vm.RegisterBuiltin("val", val)
+	vm.RegisterBuiltin("set", set)
+	vm.RegisterBuiltin("get", get)
+	vm.RegisterBuiltin("help", help)
+	vm.RegisterBuiltin("explain", explain)
+	vm.RegisterBuiltin("exit", exit)
 }
 
 

+ 30 - 4
cmd/muesli/main.go

@@ -35,21 +35,38 @@ func runLines(vm *muesli.VM, line *liner.State) error {
 		if in, err := line.Prompt("> "); err == nil {
 			err = runLine(vm, in)
 			if err != nil { 
-				fmt.Print("Error %s: \n", err)
+				os.Stderr.WriteString(fmt.Sprintf("Error %s: \n", err))
 			}
 			line.AppendHistory(in)
 		} else if err == liner.ErrPromptAborted {
-			fmt.Print("Aborted\n")
+			os.Stderr.WriteString("Aborted\n")
 			return nil
 		} else {
-			fmt.Print("Error reading line: %s\n", err)
+			os.Stderr.WriteString(fmt.Sprintf("Error reading line: %s\n", err))
 		}
 	}
 	return nil
 }
 
-func main() {
+func runFile(vm *muesli.VM, name string) error {
+	parser, err := muesli.NewParserFromFilename(name)
+	if err != nil {
+		os.Stderr.WriteString(fmt.Sprintf("Error opening file %s: %s\n", name, err))
+		return err
+	}
+	ast := parser.Parse()
+	err = ast.ToError()
+	if err != nil {
+		os.Stderr.WriteString(fmt.Sprintf("%s: execution error\n", err))
+		return err
+	}
+	vm.RunAst(*ast, muesli.NewListValue())
+	return nil
+}
+
+func main() {	
 	vm := muesli.NewVM()
+	// defer func () { os.Exit(vm.ExitStatus) }()
 	// vm.Tracer = &muesli.FmtTracer{}
 	vm.RegisterBuiltins() 
 	line := liner.NewLiner()
@@ -74,6 +91,15 @@ func main() {
 		f.Close()
 	} 
 	
+	if len(os.Args) > 0 {
+		for _, name := range os.Args {
+			err := runFile(vm, name)
+			if err != nil {
+				return
+			}
+		}
+	}
+	
 	runLines(vm, line)
 	
 	if f, err := os.Create(historyName); err != nil {

+ 27 - 5
lexer.go

@@ -98,6 +98,23 @@ func (lexer *Lexer) MakeStringValueToken(kind TokenKind) Token {
 	return NewToken(kind, StringValue(sbuffer), lexer.Position)
 }
 
+func (lexer *Lexer) MakeTypeValueToken(kind TokenKind) Token {
+	var sbuffer = string(lexer.buffer)
+	return NewToken(kind, TypeValue(sbuffer), lexer.Position)
+}
+
+func (lexer *Lexer) MakeErrorValueToken(kind TokenKind) Token {
+	var sbuffer = string(lexer.buffer)
+	return NewToken(kind, NewErrorValuef("%s", sbuffer), lexer.Position)
+}
+
+func (lexer *Lexer) MakeWordValueToken(kind TokenKind) Token {
+	var sbuffer = string(lexer.buffer)
+	return NewToken(kind, WordValue(sbuffer), lexer.Position)
+}
+
+
+
 func (lexer *Lexer) MakeToken(kind TokenKind) Token {
 	switch kind {
 	case TokenKindInteger:
@@ -105,15 +122,15 @@ func (lexer *Lexer) MakeToken(kind TokenKind) Token {
 	case TokenKindFloat:
 		return lexer.MakeFloatToken()
 	case TokenKindString:
-		fallthrough
+		return lexer.MakeStringValueToken(kind)
 	case TokenKindSymbol:
-		fallthrough
+		return lexer.MakeWordValueToken(kind)
 	case TokenKindType:
-		fallthrough
+		return lexer.MakeTypeValueToken(kind)
 	case TokenKindError:
-		fallthrough
+		return lexer.MakeErrorValueToken(kind)
 	case TokenKindWord:
-		return lexer.MakeStringValueToken(kind)
+		return lexer.MakeWordValueToken(kind)
     case TokenKindNil:
         fallthrough
 	case TokenKindBoolean:
@@ -677,6 +694,11 @@ func (lexer *Lexer) lex() Token {
 			return lexer.LexWord()
 		}
 	}
+	
+	// EOF character
+	if r == 0x7f {
+		return lexer.MakeEOFToken()
+	}
 
 	return lexer.MakeErrorfToken("Unknown character: %c", r)
 }

+ 20 - 4
parser.go

@@ -151,17 +151,34 @@ func (parser *Parser) ParseValue() *Ast {
     parser.LogDebug("ParseValue: %s\n", parser.current.String())
 
 	value := parser.Require(TokenKindInteger, TokenKindString,
-		TokenKindBoolean, TokenKindNil, TokenKindNil, TokenKindFloat, TokenKindSymbol)
+		TokenKindBoolean, TokenKindNil, TokenKindFloat, TokenKindSymbol)
 	return parser.NewAst(AstKindValue, nil, EmptyAstArray(), value)
 }
 
+func AstKindForToken(token Token) AstKind {
+	switch token.TokenKind {
+		case TokenKindInteger, TokenKindString,	TokenKindBoolean, 
+			 TokenKindNil, TokenKindFloat, TokenKindSymbol:
+			 return AstKindValue
+		case TokenKindWord:
+			 return AstKindWord
+		case TokenKindType:
+			return AstKindType
+		default:
+			return AstKindError
+	}
+}
+
 func (parser *Parser) ParseWordValue() *Ast {
     parser.LogDebug("ParseWordValue: %s\n", parser.current.String())
 
 	value := parser.Require(TokenKindInteger, TokenKindString,
-		TokenKindBoolean, TokenKindNil, TokenKindNil, TokenKindFloat, TokenKindSymbol,
+		TokenKindBoolean, TokenKindNil, TokenKindFloat, TokenKindSymbol,
 		TokenKindType, TokenKindWord)
-	return parser.NewAst(AstKindWordValue, nil, EmptyAstArray(), value)
+	
+	astKind := AstKindForToken(value)
+	
+	return parser.NewAst(astKind, nil, EmptyAstArray(), value)
 }
 
 func (parser *Parser) ParseArgument() *Ast {
@@ -187,7 +204,6 @@ func (parser *Parser) ParseArguments() *Ast {
 		children = append(children, child)
 	}
 	ast.AppendChildren(children...)
-	fmt.Printf("ParseArguments: %v\n", children)
 	return ast
 }
 

+ 4 - 0
test/testdata/test_0001.muesli

@@ -0,0 +1,4 @@
+
+p "Hello" .
+
+exit 1 .

+ 11 - 0
test/testdata/test_0002.muesli

@@ -0,0 +1,11 @@
+
+to foo { 
+	p "Foo"
+}
+
+foo
+
+p "OK"
+
+exit 0 .
+

+ 22 - 7
value.go

@@ -179,8 +179,10 @@ func (from IntValue) Convert(to interface{}) error {
 			(*toPtr) = float32(from)
 		case *float64:
 			(*toPtr) = float64(from)
+		case *IntValue:
+			(*toPtr) = from
 		default:
-			return NewErrorValuef("Cannot convert value %v to %v", from, to)
+			return NewErrorValuef("Cannot convert IntValue value %v to %v", from, to)
 	}
 	return nil
 }
@@ -205,8 +207,10 @@ func (from FloatValue) Convert(to interface{}) error {
 			(*toPtr) = float32(from)
 		case *float64:
 			(*toPtr) = float64(from)
+		case *FloatValue:
+			(*toPtr) = from
 		default:
-			return NewErrorValuef("Cannot convert value %v to %v", from, to)
+			return NewErrorValuef("Cannot convert FloatValue value %v to %v", from, to)
 	}
 	return nil
 }
@@ -215,8 +219,10 @@ func (from StringValue) Convert(to interface{}) error {
 	switch toPtr := to.(type) {
 		case *string:
 			(*toPtr) = from.String()
+		case *StringValue:
+			(*toPtr) = from	
 		default:
-			return NewErrorValuef("Cannot convert value %v to %v", from, to)
+			return NewErrorValuef("Cannot convert StringValue %v to %v", from, to)
 	}
 	return nil
 }
@@ -225,8 +231,10 @@ func (from WordValue) Convert(to interface{}) error {
 	switch toPtr := to.(type) {
 		case *string:
 			(*toPtr) = from.String()
+		case *WordValue:
+			(*toPtr) = from
 		default:
-			return NewErrorValuef("Cannot convert value %v to %v", from, to)
+			return NewErrorValuef("Cannot convert WordValue %v to %v", from, to)
 	}
 	return nil
 }
@@ -236,6 +244,8 @@ func (from TypeValue) Convert(to interface{}) error {
 	switch toPtr := to.(type) {
 		case *string:
 			(*toPtr) = from.String()
+		case *TypeValue:
+			(*toPtr) = from			
 		default:
 			return NewErrorValuef("Cannot convert value %v to %v", from, to)
 	}
@@ -247,6 +257,8 @@ func (from BoolValue) Convert(to interface{}) error {
 	switch toPtr := to.(type) {
 		case *bool:			 
 			(*toPtr) = bool(from) 		
+		case *BoolValue:
+			(*toPtr) = from		
 		default:
 			return NewErrorValuef("Cannot convert value %v to %v", from, to)
 	}
@@ -259,6 +271,8 @@ func (from ErrorValue) Convert(to interface{}) error {
 			(*toPtr) = from.String()
 		case *error:
 			(*toPtr) = from.error
+		case *ErrorValue:
+			(*toPtr) = from
 		default:
 			return NewErrorValuef("Cannot convert value %v to %v", from, to)
 	}
@@ -285,8 +299,9 @@ func From(from Value, to interface{}) error {
 	return from.Convert(to)
 }
 
-/* Helpers to easily convert Muesli value lists to "normal" Go values. */
-func ParseArgs(args []Value, to...interface{}) ([]interface{}, error) {
+/* 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))
 	}
@@ -300,7 +315,7 @@ func ParseArgs(args []Value, to...interface{}) ([]interface{}, error) {
 		}
 	}
 	rest := args[i:len(args)]
-	return ListFromList(rest), nil
+	return rest, nil
 }
 
 /* Helpers to easily convert Muesli value lists to "normal" Go values in slices. */

+ 133 - 14
vm.go

@@ -15,11 +15,44 @@ type Caller interface {
 	Call(vm *VM, arguments ...Value) []Value
 }
 
+// A helper Value has a help text available.
+// This help text can be set as well.
+type Helper interface {
+	Help() string
+	SetHelp(string) string
+}
+
+
 // Callable value types
 type CallableValue struct {
+	// Name of the callable
 	Name string
+	// Help string for the callable.
+	HelpText string
+}
+
+// Implement Helper interface
+func (val CallableValue) Help() string {
+	return val.HelpText
+}
+
+// Implement Helper interface
+func (val * CallableValue) SetHelp(help string) string {
+	val.HelpText = help
+	return val.HelpText
+}
+
+// AppendHelp appends help to an existing helper. 
+func AppendHelp(helper Helper, extra string) string {
+	return helper.SetHelp( helper.Help() + extra)
 }
 
+// ClearHelp rresets the help text to an empty string.
+func ClearHelp(helper Helper, extra string) string {
+	return helper.SetHelp("")
+}
+
+
 func (val CallableValue) String() string {
 	return val.Name
 }
@@ -43,7 +76,7 @@ type BuiltinValue struct {
 }
 
 func NewCallableValue(name string) CallableValue {
-	return CallableValue{name}
+	return CallableValue{name, ""}
 }
 
 func NewBuiltinValue(name string, handler Handler) *BuiltinValue {
@@ -57,21 +90,67 @@ func (builtin *BuiltinValue) Call(vm *VM, arguments ...Value) []Value {
 	return vm.CallBuiltin(builtin.Handler, arguments...)
 }
 
+// A block in a script.
+type BlockValue struct {
+	CallableValue
+	Ast *Ast
+}
+
+func NewBlockValue(definition *Ast) *BlockValue {
+	result := &BlockValue{}
+	result.Name = fmt.Sprintf("<block:%s>", definition.String())
+	result.Ast = definition
+	return result
+}
+
+func (block *BlockValue) Call(vm *VM, arguments ...Value) []Value {
+	res := vm.CallBlock(block.Ast, arguments...)
+	return res
+}
+
+
+/* Parameters for a defined value */
+type Parameter struct {
+	Name WordValue
+	Type TypeValue
+}
+
+
 // A script defined function
 type DefinedValue struct {
 	CallableValue
-	Definition *Ast
+	Body *BlockValue
+	Parameters []*Parameter
 }
 
-func NewDefinedValue(name string, definition *Ast) *DefinedValue {
+func NewDefinedValue(name string, params []*Parameter, body *BlockValue) *DefinedValue {
 	result := &DefinedValue{}
 	result.Name = name
-	result.Definition = definition
+	result.Body = body
+	result.Parameters = params
 	return result
 }
 
 func (defined *DefinedValue) Call(vm *VM, arguments ...Value) []Value {
-	return vm.CallDefined(defined.Definition, arguments...)
+	defer vm.PopFrame()
+	defer vm.PopScope()
+	vm.PushNewFrame()
+	vm.PushNewScope()
+	for i , arg := range arguments {
+		if i >= len(defined.Parameters) {
+			break
+		}
+		param := defined.Parameters[i]
+		expectedType := param.Type
+		if !expectedType.IsMatch(arg.Type()) {
+			return Fail(NewErrorValuef("Argument %d type mismatch: %s<->%s", i, expectedType, arg.Type()))
+		}
+		vm.Register(param.Name.String(), arg)
+	}
+	
+	res := defined.Body.Call(vm, arguments...)
+	return res
+
 }
 
 /*
@@ -167,11 +246,13 @@ const (
 	CoverTypeValue   = TypeValue("Cover")
 	BuiltinTypeValue = TypeValue("Builtin")
 	DefinedTypeValue = TypeValue("Defined")
+	BlockTypeValue = TypeValue("Block")
 )
 
 func (v CoverValue) Type() TypeValue   { return CoverTypeValue }
 func (v BuiltinValue) Type() TypeValue { return BuiltinTypeValue }
 func (v DefinedValue) Type() TypeValue { return DefinedTypeValue }
+func (v BlockValue) Type() TypeValue { return BlockTypeValue }
 
 func (from CoverValue) Convert(to interface{}) error {
 	return NewErrorValuef("Cannot convert the cover value %v to %v", from, to)
@@ -185,8 +266,17 @@ func (from DefinedValue) Convert(to interface{}) error {
 	return NewErrorValuef("Cannot convert the defined value %v to %v", from, to)
 }
 
+func (from BlockValue) Convert(to interface{}) error {
+	if toValue, isOk := to.(*BlockValue) ; isOk {
+		(*toValue) = from
+		return nil
+	} 
+	return NewErrorValuef("Cannot convert the block value %v to %v", from, to)
+}
+
+
 func (cv * CoverValue) AddOverload(callable Caller, tv ... TypeValue) error {
-	fmt.Printf("AddOverload: %v\n", tv)
+	// fmt.Printf("AddOverload: %v\n", tv)
 	
 	signature := Signature{}
 	length := len(tv)
@@ -200,7 +290,7 @@ func (cv * CoverValue) AddOverload(callable Caller, tv ... TypeValue) error {
 		
 	cv.Overloads[signature] = Overload { callable } 
 	
-	fmt.Printf("Overloads: %v\n", cv.Overloads)
+	// fmt.Printf("Overloads: %v\n", cv.Overloads)
 	
 	return nil
 }
@@ -216,24 +306,38 @@ func (vm * VM) AddOverload(from, target string, tv... TypeValue) error {
 		return fmt.Errorf("%s exists and is not a cover value", from)
 	}
 	
-	fmt.Printf("AddOverload: %v %v\n", lookup, cover)
+	// fmt.Printf("AddOverload: %v %v\n", lookup, cover)
 	
 	lookup = vm.Lookup(target)
 	if lookup == nil { 
 		return fmt.Errorf("target %s is not defined", target)
 	}
-	fmt.Printf("AddOverload lookup: %v\n", lookup)
+	// fmt.Printf("AddOverload lookup: %v\n", lookup)
 	
 	if callable, ok = lookup.(Caller) ; !ok {
 		return fmt.Errorf("%s is not a callable value", target)
 	}
 	res := cover.AddOverload(callable, tv...)
 	
-	fmt.Printf("AddOverload: %v %v\n", lookup, cover)
+	// fmt.Printf("AddOverload: %v %v\n", lookup, cover)
 	
 	return res
 } 
 
+func (vm * VM) SetHelp(target, help string) error {
+	var helper Helper
+	var ok bool	
+	lookup := vm.Lookup(target)
+	if lookup == nil {
+		return fmt.Errorf("%s not found", target) 
+	} else if helper, ok = lookup.(Helper) ; !ok {
+		return fmt.Errorf("%s exists but cannot set help text.", target)
+	}
+	helper.SetHelp(help)	
+	return nil
+} 
+
+
 // Scope of symbols defined in the VM, hierarchical
 type Scope struct {
 	parent   *Scope
@@ -296,10 +400,11 @@ type VM struct {
 	*Scope          // Current Scope
 	*Frame          // Current frame
 	Tracer			// Tracer to emit tracing info to, could be used for logging or debugging
+	ExitStatus int
 }
 
 func NewVM() *VM {
-	vm := &VM{NewScope(nil), NewFrame(nil), nil, nil, nil}
+	vm := &VM{NewScope(nil), NewFrame(nil), nil, nil, nil, 0}
 	vm.Scope = vm.TopScope
 	vm.Frame = vm.TopFrame
 	return vm
@@ -340,6 +445,11 @@ func (vm *VM) CallDefined(ast *Ast, arguments ...Value) []Value {
 	return arr
 }
 
+func (vm *VM) CallBlock(ast *Ast, arguments ...Value) []Value {
+	arr := vm.RunChildren(*ast, arguments...)
+	return arr
+}
+
 func (vm *VM) CallBuiltin(handler Handler, arguments ...Value) []Value {
 	return handler.Call(vm, arguments...)
 }
@@ -355,9 +465,11 @@ func (vm *VM) CallNamed(name string, arguments ...Value) []Value {
 	case *BuiltinValue:
 		return vm.CallBuiltin(toCall.Handler, arguments...)
 	case *DefinedValue:
-		return vm.CallDefined(toCall.Definition, arguments...)
+		return vm.CallDefined(toCall.Body.Ast, arguments...)
 	case *CoverValue:
 		return vm.CallCover(toCall, arguments...)
+	case *BlockValue:
+		return vm.CallBlock(toCall.Ast, arguments...)	
 	default:
 		return ReturnError(NewErrorValuef("Cannot call %s: %v", name, value))
 	}
@@ -385,11 +497,18 @@ func (vm *VM) RegisterBuiltin(name string, handler Handler) Value {
 	return vm.Register(name, value)
 }
 
-func (vm *VM) RegisterDefined(name string, ast *Ast) Value {
-	value := NewDefinedValue(name, ast)
+func (vm *VM) RegisterDefined(name string, params []*Parameter, block *BlockValue) Value {
+	value := NewDefinedValue(name, params, block)
 	return vm.Register(name, value)
 }
 
+// RegisterBuiltinWithHelp
+func (vm *VM) RegisterBuiltinWithHelp(name string, handler Handler, help string) Value {
+	res := vm.RegisterBuiltin(name, handler)
+	vm.SetHelp(name, help)
+	return res
+}
+
 func (vm *VM) Fail() {
 	vm.Frame.failed = true
 }