diff --git a/main.go b/main.go index 36d4acab..ccfb3ef0 100644 --- a/main.go +++ b/main.go @@ -41,8 +41,8 @@ func (c *cmdRun) Run() error { if err != nil { return err } - print := func(s string) { fmt.Print(s) } - evaluator.Run(string(b), print) + printFunc := func(s string) { fmt.Print(s) } + evaluator.Run(string(b), printFunc) return nil } @@ -61,7 +61,9 @@ func (c *cmdParse) Run() error { if err != nil { return err } - result := parser.Run(string(b)) + printFunc := func(s string) { fmt.Print(s) } + builtins := evaluator.DefaultBuiltins(printFunc).Decls() + result := parser.Run(string(b), builtins) fmt.Println(result) return nil } diff --git a/pkg/evaluator/evaluator.go b/pkg/evaluator/evaluator.go index 0573971e..0dcdb881 100644 --- a/pkg/evaluator/evaluator.go +++ b/pkg/evaluator/evaluator.go @@ -5,8 +5,11 @@ import ( ) func Run(input string, print func(string)) { - builtins := DefaultBuiltins(print) - p := parser.NewWithBuiltins(input, builtins.Decls()) + RunWithBuiltins(input, print, DefaultBuiltins(print)) +} + +func RunWithBuiltins(input string, print func(string), builtins Builtins) { + p := parser.New(input, builtins.Decls()) prog := p.Parse() if p.HasErrors() { print(p.MaxErrorsString(8)) diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index 5ad80c30..5216ca8f 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -7,8 +7,8 @@ import ( "foxygo.at/evy/pkg/lexer" ) -func Run(input string) string { - parser := New(input) +func Run(input string, builtins map[string]*FuncDecl) string { + parser := New(input, builtins) prog := parser.Parse() if len(parser.errors) > 0 { errs := make([]string, len(parser.errors)) @@ -41,11 +41,7 @@ func (e Error) String() string { return e.token.Location() + ": " + e.message } -func New(input string) *Parser { - return NewWithBuiltins(input, builtins()) -} - -func NewWithBuiltins(input string, builtins map[string]*FuncDecl) *Parser { +func New(input string, builtins map[string]*FuncDecl) *Parser { l := lexer.New(input) p := &Parser{funcs: builtins} @@ -74,21 +70,6 @@ func NewWithBuiltins(input string, builtins map[string]*FuncDecl) *Parser { return p } -func builtins() map[string]*FuncDecl { - return map[string]*FuncDecl{ - "print": &FuncDecl{ - Name: "print", - VariadicParam: &Var{Name: "a", T: ANY_TYPE}, - ReturnType: NONE_TYPE, - }, - "len": &FuncDecl{ - Name: "len", - Params: []*Var{{Name: "a", T: ANY_TYPE}}, - ReturnType: NUM_TYPE, - }, - } -} - func (p *Parser) Errors() []Error { return p.errors } diff --git a/pkg/parser/parser_test.go b/pkg/parser/parser_test.go index 6208e9c6..333cb30c 100644 --- a/pkg/parser/parser_test.go +++ b/pkg/parser/parser_test.go @@ -33,7 +33,7 @@ func TestParseDeclaration(t *testing.T) { } for input, wantSlice := range tests { want := strings.Join(wantSlice, "\n") + "\n" - parser := New(input) + parser := New(input, testBuiltins()) got := parser.Parse() assertNoParseError(t, parser, input) assert.Equal(t, want, got.String()) @@ -53,7 +53,7 @@ func TestEmptyProgram(t *testing.T) { " \n //blabla", } for _, input := range tests { - parser := New(input) + parser := New(input, testBuiltins()) got := parser.Parse() assertNoParseError(t, parser, input) assert.Equal(t, "\n", got.String()) @@ -82,7 +82,7 @@ func TestParseDeclarationError(t *testing.T) { "a :num{}num": "line 1 column 9: expected end of line, found 'num'", } for input, err1 := range tests { - parser := New(input) + parser := New(input, testBuiltins()) _ = parser.Parse() assertParseError(t, parser, input) assert.Equal(t, err1, parser.errors[0].String(), "input: %s\nerrors:\n%s", input, parser.ErrorsString()) @@ -105,7 +105,7 @@ func TestFunctionCall(t *testing.T) { } for input, wantSlice := range tests { want := strings.Join(wantSlice, "\n") + "\n" - parser := New(input) + parser := New(input, testBuiltins()) got := parser.Parse() assertNoParseError(t, parser, input) assert.Equal(t, want, got.String()) @@ -113,7 +113,7 @@ func TestFunctionCall(t *testing.T) { } func TestFunctionCallError(t *testing.T) { - builtins := builtins() + builtins := testBuiltins() builtins["f0"] = &FuncDecl{Name: "f0", ReturnType: NONE_TYPE} builtins["f1"] = &FuncDecl{Name: "f1", VariadicParam: &Var{Name: "a", T: NUM_TYPE}, ReturnType: NONE_TYPE} builtins["f2"] = &FuncDecl{Name: "f2", Params: []*Var{&Var{Name: "a", T: NUM_TYPE}}, ReturnType: NONE_TYPE} @@ -135,7 +135,7 @@ func TestFunctionCallError(t *testing.T) { `foo 0`: "line 1 column 1: unknown function 'foo'", } for input, err1 := range tests { - parser := NewWithBuiltins(input, builtins) + parser := New(input, builtins) _ = parser.Parse() assertParseError(t, parser, input) assert.Equal(t, err1, parser.errors[0].String(), "input: %s\nerrors:\n%s", input, parser.ErrorsString()) @@ -155,7 +155,7 @@ func TestBlock(t *testing.T) { } for input, wantSlice := range tests { want := strings.Join(wantSlice, "\n") + "\n" - parser := New(input) + parser := New(input, testBuiltins()) got := parser.Parse() assertNoParseError(t, parser, input) assert.Equal(t, want, got.String()) @@ -166,7 +166,7 @@ func TestToplevelExprFuncCall(t *testing.T) { input := ` x := len "123" ` - parser := New(input) + parser := New(input, testBuiltins()) got := parser.Parse() assertNoParseError(t, parser, input) want := ` @@ -190,10 +190,10 @@ on mousedown end end ` - parser := New(input) + parser := New(input, testBuiltins()) _ = parser.Parse() assertNoParseError(t, parser, input) - builtinCnt := len(builtins()) + builtinCnt := len(testBuiltins()) assert.Equal(t, builtinCnt+1, len(parser.funcs)) got := parser.funcs["add"] assert.Equal(t, "add", got.Name) @@ -233,7 +233,7 @@ end `, } for _, input := range inputs { - parser := New(input) + parser := New(input, testBuiltins()) _ = parser.Parse() assertNoParseError(t, parser, input) } @@ -304,7 +304,7 @@ end `: "line 2 column 8: invalid declaration of parameter 'x', already used as function name", } for input, wantErr := range inputs { - parser := New(input) + parser := New(input, testBuiltins()) _ = parser.Parse() assertParseError(t, parser, input) assert.Equal(t, wantErr, parser.errors[0].String()) @@ -321,7 +321,7 @@ print "x:" x if x > 10 print "🍦 big x" end` - parser := New(input) + parser := New(input, testBuiltins()) got := parser.Parse() assertParseError(t, parser, input) assert.Equal(t, "line 2 column 1: unknown function 'move'", parser.errors[0].String()) @@ -342,3 +342,18 @@ func assertNoParseError(t *testing.T, parser *Parser, input string) { t.Helper() assert.Equal(t, 0, len(parser.errors), "Unexpected parser error\n input: %s\nerrors:\n%s", input, parser.ErrorsString()) } + +func testBuiltins() map[string]*FuncDecl { + return map[string]*FuncDecl{ + "print": &FuncDecl{ + Name: "print", + VariadicParam: &Var{Name: "a", T: ANY_TYPE}, + ReturnType: NONE_TYPE, + }, + "len": &FuncDecl{ + Name: "len", + Params: []*Var{{Name: "a", T: ANY_TYPE}}, + ReturnType: NUM_TYPE, + }, + } +} diff --git a/pkg/wasm/main.go b/pkg/wasm/main.go index 3acd0eca..bf3dbb25 100644 --- a/pkg/wasm/main.go +++ b/pkg/wasm/main.go @@ -41,7 +41,8 @@ func jsTokenize(ptr *uint32, length int) { //export parse func jsParse(ptr *uint32, length int) { s := getString(ptr, length) - jsPrint(parser.Run(s)) + builtins := evaluator.DefaultBuiltins(jsPrint).Decls() + jsPrint(parser.Run(s, builtins)) } // alloc pre-allocates memory used in string parameter passing.