summaryrefslogtreecommitdiff
path: root/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'codegen')
-rw-r--r--codegen/compiler.go36
-rw-r--r--codegen/compiler_test.go8
-rw-r--r--codegen/interpreter_test.go47
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",
+}}