summaryrefslogtreecommitdiff
path: root/parser/interpreter.go
diff options
context:
space:
mode:
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
+}