summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2023-09-04 16:58:15 +0200
committerMarc Vertes <mvertes@free.fr>2023-09-04 16:58:15 +0200
commit4241593b42bffac2f8fcb63f1e88621fe025e360 (patch)
tree48680879982947524e1b028e179608bb5cbcda23
parent8feddd9b3eefb920c4a0c7a5b4c3b8ae160f3c71 (diff)
codegen: add interpreter tests
Also simplify project structure. The executable is now produced in the root directory. Work in progress.
-rw-r--r--codegen/compiler.go36
-rw-r--r--codegen/compiler_test.go8
-rw-r--r--codegen/interpreter_test.go47
-rw-r--r--main.go (renamed from cmd/gint/main.go)0
-rw-r--r--scanner/scan.go2
-rw-r--r--testdata/add (renamed from samples/add)0
-rw-r--r--testdata/fib (renamed from samples/fib)0
-rw-r--r--testdata/p00 (renamed from samples/p00)0
-rw-r--r--testdata/p01 (renamed from samples/p01)0
-rw-r--r--testdata/p02 (renamed from samples/p02)0
-rw-r--r--testdata/p03 (renamed from samples/p03)0
-rw-r--r--testdata/p04 (renamed from samples/p04)0
-rw-r--r--testdata/p05 (renamed from samples/p05)0
-rw-r--r--testdata/p06 (renamed from samples/p06)0
-rw-r--r--testdata/p075
-rw-r--r--vm1/vm.go3
16 files changed, 92 insertions, 9 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",
+}}
diff --git a/cmd/gint/main.go b/main.go
index 037614c..037614c 100644
--- a/cmd/gint/main.go
+++ b/main.go
diff --git a/scanner/scan.go b/scanner/scan.go
index 914f4bc..1cc36a7 100644
--- a/scanner/scan.go
+++ b/scanner/scan.go
@@ -108,7 +108,7 @@ func (sc *Scanner) IsId(r rune) bool {
}
func (sc *Scanner) Init() {
- // Build a regular expression to match all string delimiters.
+ // Build a regular expression to match all string start delimiters at once.
re := "("
for s, p := range sc.BlockProp {
if p&CharStr == 0 {
diff --git a/samples/add b/testdata/add
index a403485..a403485 100644
--- a/samples/add
+++ b/testdata/add
diff --git a/samples/fib b/testdata/fib
index 654c5c0..654c5c0 100644
--- a/samples/fib
+++ b/testdata/fib
diff --git a/samples/p00 b/testdata/p00
index 19f5084..19f5084 100644
--- a/samples/p00
+++ b/testdata/p00
diff --git a/samples/p01 b/testdata/p01
index baafaa9..baafaa9 100644
--- a/samples/p01
+++ b/testdata/p01
diff --git a/samples/p02 b/testdata/p02
index 1aeb4a9..1aeb4a9 100644
--- a/samples/p02
+++ b/testdata/p02
diff --git a/samples/p03 b/testdata/p03
index 39a3cda..39a3cda 100644
--- a/samples/p03
+++ b/testdata/p03
diff --git a/samples/p04 b/testdata/p04
index f2a85c8..f2a85c8 100644
--- a/samples/p04
+++ b/testdata/p04
diff --git a/samples/p05 b/testdata/p05
index 51c2c9b..51c2c9b 100644
--- a/samples/p05
+++ b/testdata/p05
diff --git a/samples/p06 b/testdata/p06
index 88029cc..88029cc 100644
--- a/samples/p06
+++ b/testdata/p06
diff --git a/testdata/p07 b/testdata/p07
new file mode 100644
index 0000000..2fa7ee0
--- /dev/null
+++ b/testdata/p07
@@ -0,0 +1,5 @@
+func f1() { println("in f1") }
+
+func f2() { println("in f2"); f1() }
+
+f2()
diff --git a/vm1/vm.go b/vm1/vm.go
index 572a171..01bba83 100644
--- a/vm1/vm.go
+++ b/vm1/vm.go
@@ -2,6 +2,7 @@ package vm1
import (
"fmt" // for tracing only
+ "log" // for tracing only
"reflect" // for optional CallX only
"strconv" // for tracing only
)
@@ -79,7 +80,7 @@ func (m *Machine) Run() (err error) {
op3 = strconv.Itoa(int(c[3]))
}
}
- fmt.Printf("ip:%-4d sp:%-4d fp:%-4d op:[%-9s %-4s %-4s] mem:%v\n", ip, sp, fp, strop[c[1]], op2, op3, mem)
+ log.Printf("ip:%-4d sp:%-4d fp:%-4d op:[%-9s %-4s %-4s] mem:%v\n", ip, sp, fp, strop[c[1]], op2, op3, mem)
}
for {