summaryrefslogtreecommitdiff
path: root/parser/interpreter.go
diff options
context:
space:
mode:
authorMarc Vertes <marc.vertes@tendermint.com>2023-10-12 10:51:58 +0200
committerGitHub <noreply@github.com>2023-10-12 10:51:58 +0200
commit37b9da32d3b911091deb254f6cba2a137c471287 (patch)
treeb4451de0fa0473a937a77d39fd1f8a4f87c8f60d /parser/interpreter.go
parenta21b9b12ad865a19ff687645082f9093c4101039 (diff)
move to a direct byte code compiler (#8)
* chore: refactor to keep only the new parser and bytecode vm * scanner: remove Token.value field * scanner: remove scanner.kind field * chore: move language specification in lang package This avoid a cyclic dependency in scanner_test which can now use the golang/GoSpec language specification for Go. * clean code * scanner: export scanner fields Also parser now generate function calls, including externals. * chore: fix lint issues * parser: handle strings * wip * parser: implement support for 'if, else, else if' statements Resolving labels in the compiler still in progress. * parser: support if statements, improve compiler * improve handling of functions * improve support of local variables * scanner: trim leading and trailing spaces * fixes to make fibonacci work * parser: improve README, fix function parameters parsing
Diffstat (limited to 'parser/interpreter.go')
-rw-r--r--parser/interpreter.go52
1 files changed, 52 insertions, 0 deletions
diff --git a/parser/interpreter.go b/parser/interpreter.go
new file mode 100644
index 0000000..72fc667
--- /dev/null
+++ b/parser/interpreter.go
@@ -0,0 +1,52 @@
+package parser
+
+import (
+ "github.com/gnolang/parscan/scanner"
+ "github.com/gnolang/parscan/vm"
+)
+
+const debug = true
+
+type Interpreter struct {
+ *Compiler
+ *vm.Machine
+}
+
+func NewInterpreter(s *scanner.Scanner) *Interpreter {
+ return &Interpreter{NewCompiler(s), &vm.Machine{}}
+}
+
+func (i *Interpreter) Eval(src string) (res any, err error) {
+ codeOffset := len(i.Code)
+ dataOffset := 0
+ if codeOffset > 0 {
+ // All data must be copied to the VM the first time only (re-entrance).
+ dataOffset = len(i.Data)
+ }
+ i.PopExit() // Remove last exit from previous run (re-entrance).
+
+ t, err := i.Parse(src)
+ if err != nil {
+ return res, err
+ }
+ if err = i.Codegen(t); err != nil {
+ return res, err
+ }
+ i.Push(i.Data[dataOffset:]...)
+ i.PushCode(i.Code[codeOffset:]...)
+ i.PushCode([]int64{0, vm.Exit})
+ i.SetIP(max(codeOffset, i.Entry))
+ if debug {
+ i.PrintData()
+ i.PrintCode()
+ }
+ err = i.Run()
+ return i.Top(), err
+}
+
+func max(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}