summaryrefslogtreecommitdiff
path: root/codegen/interpreter.go
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2023-08-31 17:53:54 +0200
committerMarc Vertes <mvertes@free.fr>2023-08-31 17:53:54 +0200
commit851c793da43be9e4d3319afe440d603c85834045 (patch)
treefd4b3d3812f5743213b5849858c459c8196dbf7f /codegen/interpreter.go
parent0f4bfe6e70263fbeb580014b62632f403b29b414 (diff)
codegen: fix interpreter re-entrance
So multiple successive incremental Evals function correctly. Also improve the following: - Apply the same Eval API to vm0 and vm1 - parser: dot diagram display is now synchronous - codegen: outsource complex code generation for readability - vm1: Pop take the number of values to pop as operand
Diffstat (limited to 'codegen/interpreter.go')
-rw-r--r--codegen/interpreter.go24
1 files changed, 15 insertions, 9 deletions
diff --git a/codegen/interpreter.go b/codegen/interpreter.go
index b26b403..a3268d9 100644
--- a/codegen/interpreter.go
+++ b/codegen/interpreter.go
@@ -19,24 +19,30 @@ func NewInterpreter(p *parser.Parser) *Interpreter {
return &Interpreter{p, NewCompiler(), &vm1.Machine{}}
}
-func (i *Interpreter) Eval(src string) (err error) {
+func (i *Interpreter) Eval(src string) (res any, err error) {
n := &parser.Node{}
if n.Child, err = i.Parse(src); err != nil {
- return err
+ return res, err
}
if debug {
n.Dot(os.Getenv("DOT"), "")
}
- offset := len(i.Code)
- i.PopExit() // Remove last exit from previous run.
+ 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).
if err = i.CodeGen(n); err != nil {
- return err
+ return res, err
}
- i.Push(i.Data...)
- i.PushCode(i.Code[offset:]...)
+ i.Push(i.Data[dataOffset:]...)
+ i.PushCode(i.Code[codeOffset:]...)
i.PushCode([]int64{0, vm1.Exit})
- i.SetIP(max(offset, i.Entry))
- return i.Run()
+ i.SetIP(max(codeOffset, i.Entry))
+ err = i.Run()
+ return i.Top(), err
}
func max(a, b int) int {