diff options
Diffstat (limited to 'codegen')
| -rw-r--r-- | codegen/compiler.go | 36 | ||||
| -rw-r--r-- | codegen/compiler_test.go | 8 | ||||
| -rw-r--r-- | codegen/interpreter_test.go | 47 |
3 files changed, 84 insertions, 7 deletions
diff --git a/codegen/compiler.go b/codegen/compiler.go index 3952166..30fc070 100644 --- a/codegen/compiler.go +++ b/codegen/compiler.go @@ -2,6 +2,7 @@ package codegen import ( "fmt" + "log" "strings" "github.com/gnolang/parscan/parser" @@ -84,8 +85,14 @@ func (c *Compiler) CodeGen(node *parser.Node) (err error) { c.Emit(n, vm1.Assign, int64(l)) case parser.DeclFunc: + fun := frameNode[len(frameNode)-1] + if len(fun.Child) == 3 { // no return values + if c.Code[len(c.Code)-1][1] != vm1.Return { + c.Emit(n, vm1.Return, 0, int64(len(fun.Child[1].Child))) + } + } scope = popScope(scope) - fnote = notes[frameNode[len(frameNode)-1]] + fnote = notes[fun] case parser.Ident: ident := n.Content() @@ -121,7 +128,15 @@ func (c *Compiler) CodeGen(node *parser.Node) (err error) { case parser.StmtReturn: fun := frameNode[len(frameNode)-1] - c.Emit(n, vm1.Return, int64(len(n.Child)), int64(len(fun.Child[1].Child))) + nret := 0 + if len(fun.Child) > 3 { + if ret := fun.Child[2]; ret.Kind == parser.BlockParen { + nret = len(ret.Child) + } else { + nret = 1 + } + } + c.Emit(n, vm1.Return, int64(nret), int64(len(fun.Child[1].Child))) case parser.BlockStmt: nd.ipend = len(c.Code) @@ -151,6 +166,17 @@ func (c *Compiler) CodeGen(node *parser.Node) (err error) { } return true }) + + log.Println("main:", c.symbols["main"]) + if s, _, ok := c.getSym("main", ""); ok { + if i, ok := c.codeIndex(s); ok { + // Internal call is always relative to instruction pointer. + c.Emit(nil, vm1.Call, int64(i-len(c.Code))) + c.Entry = len(c.Code) - 1 + } + log.Println(vm1.Disassemble(c.Code)) + } + return } @@ -168,7 +194,11 @@ func (c *Compiler) addSym(v any, name string, local bool, n *parser.Node) int { } func (c *Compiler) Emit(n *parser.Node, op ...int64) int { - op = append([]int64{int64(n.Pos())}, op...) + var pos int64 + if n != nil { + pos = int64(n.Pos()) + } + op = append([]int64{pos}, op...) l := len(c.Code) c.Code = append(c.Code, op) return l diff --git a/codegen/compiler_test.go b/codegen/compiler_test.go index a876d52..fbe8bb2 100644 --- a/codegen/compiler_test.go +++ b/codegen/compiler_test.go @@ -12,7 +12,7 @@ import ( func TestCodeGen(t *testing.T) { log.SetFlags(log.Lshortfile) - for _, test := range tests { + for _, test := range codeGenTests { test := test t.Run("", func(t *testing.T) { c := NewCompiler() @@ -32,13 +32,13 @@ func TestCodeGen(t *testing.T) { t.Log("data:", c.Data) t.Log("code:", vm1.Disassemble(c.Code)) if s := vm1.Disassemble(c.Code); s != test.asm { - t.Errorf("got error %#v, want error %#v", s, test.asm) + t.Errorf("got %#v, want %#v", s, test.asm) } }) } } -var tests = []struct { +var codeGenTests = []struct { src, asm, sym, err string }{{ // #00 src: "1+2", @@ -55,4 +55,4 @@ var tests = []struct { }, { // #04 src: "func add(a int, b int) int { return a + b }", asm: "Fdup -2\nFdup -3\nAdd\nReturn 1 2\n", -}, {}} +}} diff --git a/codegen/interpreter_test.go b/codegen/interpreter_test.go new file mode 100644 index 0000000..1d8a6b5 --- /dev/null +++ b/codegen/interpreter_test.go @@ -0,0 +1,47 @@ +package codegen + +import ( + "fmt" + "log" + "testing" + + "github.com/gnolang/parscan/lang/golang" +) + +func TestEval(t *testing.T) { + for _, test := range evalTests { + test := test + t.Run("", func(t *testing.T) { + interp := NewInterpreter(golang.GoParser) + errStr := "" + r, e := interp.Eval(test.src) + if e != nil { + errStr = e.Error() + } + if errStr != test.err { + t.Errorf("got error %#v, want error %#v", errStr, test.err) + } + res := fmt.Sprintf("%v", r) + if res != test.res { + t.Errorf("got %#v, want %#v", res, test.res) + } + log.Println(r, e) + }) + } +} + +var evalTests = []struct { + name, src, res, err string +}{{ /* #00 */ + src: "1 + 2", + res: "3", +}, { // #01 + src: "a := 2; a = a + 3", + res: "5", +}, { // #02 + src: "func f(a int) int { return a + 1 }; f(5)", + res: "6", +}, { // #03 + src: "func f(a int) (b int) { b = a + 1; return }; f(5)", + res: "6", +}} |
