summaryrefslogtreecommitdiff
path: root/vm/vm.go
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2023-11-07 21:49:01 +0100
committerMarc Vertes <mvertes@free.fr>2023-11-07 21:49:01 +0100
commitbb783f8f31797597ca0349434e236e6df923e14b (patch)
treea0a04a3cae098366d692e892c89a7e9fe614452b /vm/vm.go
parent819826627f90aecdd1d91e24563fe2162061ccf2 (diff)
parser: implement switch statement
A VM instruction `EqualSet` has been added to preserve the left operand on the stack in case of failure, to allow efficient multiple tests on the same value. Both the pattern 'if/else if' and the classical case clauses have been implemented.
Diffstat (limited to 'vm/vm.go')
-rw-r--r--vm/vm.go12
1 files changed, 12 insertions, 0 deletions
diff --git a/vm/vm.go b/vm/vm.go
index 0be9514..6f2df12 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -22,6 +22,7 @@ const (
Dup // addr -- value ; value = mem[addr]
Fdup // addr -- value ; value = mem[addr]
Equal // n1 n2 -- cond ; cond = n1 == n2
+ EqualSet // n1 n2 -- n1 cond ; cond = n1 == n2
Exit // -- ;
Greater // n1 n2 -- cond; cond = n1 > n2
Jump // -- ; ip += $1
@@ -48,6 +49,7 @@ var strop = [...]string{ // for VM tracing.
CallX: "CallX",
Dup: "Dup",
Equal: "Equal",
+ EqualSet: "EqualSet",
Exit: "Exit",
Fassign: "Fassign",
Fdup: "Fdup",
@@ -141,6 +143,16 @@ func (m *Machine) Run() (err error) {
case Equal:
mem[sp-2] = mem[sp-2].(int) == mem[sp-1].(int)
mem = mem[:sp-1]
+ case EqualSet:
+ if mem[sp-2].(int) == mem[sp-1].(int) {
+ // If equal then lhs and rhs are popped, replaced by test result, as in Equal.
+ mem[sp-2] = true
+ mem = mem[:sp-1]
+ } else {
+ // If not equal then the lhs is let on stack for further processing.
+ // This is used to simplify bytecode in case clauses of switch statments.
+ mem[sp-1] = false
+ }
case Exit:
return err
case Fdup: