summaryrefslogtreecommitdiff
path: root/vm
diff options
context:
space:
mode:
Diffstat (limited to 'vm')
-rw-r--r--vm/op_string.go57
-rw-r--r--vm/vm.go243
-rw-r--r--vm/vm_test.go264
3 files changed, 281 insertions, 283 deletions
diff --git a/vm/op_string.go b/vm/op_string.go
new file mode 100644
index 0000000..ef3f3ee
--- /dev/null
+++ b/vm/op_string.go
@@ -0,0 +1,57 @@
+// Code generated by "stringer -type=Op"; DO NOT EDIT.
+
+package vm
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[Nop-0]
+ _ = x[Add-1]
+ _ = x[Addr-2]
+ _ = x[Assign-3]
+ _ = x[Fassign-4]
+ _ = x[Vassign-5]
+ _ = x[Call-6]
+ _ = x[Calli-7]
+ _ = x[CallX-8]
+ _ = x[Deref-9]
+ _ = x[Dup-10]
+ _ = x[Fdup-11]
+ _ = x[Equal-12]
+ _ = x[EqualSet-13]
+ _ = x[Exit-14]
+ _ = x[Field-15]
+ _ = x[Greater-16]
+ _ = x[Grow-17]
+ _ = x[Index-18]
+ _ = x[Jump-19]
+ _ = x[JumpTrue-20]
+ _ = x[JumpFalse-21]
+ _ = x[JumpSetTrue-22]
+ _ = x[JumpSetFalse-23]
+ _ = x[Lower-24]
+ _ = x[Loweri-25]
+ _ = x[Mul-26]
+ _ = x[New-27]
+ _ = x[Not-28]
+ _ = x[Pop-29]
+ _ = x[Push-30]
+ _ = x[Return-31]
+ _ = x[Sub-32]
+ _ = x[Subi-33]
+}
+
+const _Op_name = "NopAddAddrAssignFassignVassignCallCalliCallXDerefDupFdupEqualEqualSetExitFieldGreaterGrowIndexJumpJumpTrueJumpFalseJumpSetTrueJumpSetFalseLowerLoweriMulNewNotPopPushReturnSubSubi"
+
+var _Op_index = [...]uint8{0, 3, 6, 10, 16, 23, 30, 34, 39, 44, 49, 52, 56, 61, 69, 73, 78, 85, 89, 94, 98, 106, 115, 126, 138, 143, 149, 152, 155, 158, 161, 165, 171, 174, 178}
+
+func (i Op) String() string {
+ idx := int(i) - 0
+ if i < 0 || idx >= len(_Op_index)-1 {
+ return "Op(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _Op_name[_Op_index[idx]:_Op_index[idx+1]]
+}
diff --git a/vm/vm.go b/vm/vm.go
index 3cb9358..0aedaef 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -5,126 +5,98 @@ import (
"fmt" // for tracing only
"log" // for tracing only
"reflect" // for optional CallX only
- "strconv" // for tracing only
"unsafe" // to allow setting unexported struct fields
)
const debug = true
+type (
+ Op int // Op is a VM opcode (bytecode instruction).
+ Pos int // Pos is the source code position of instruction
+)
+
+//go:generate stringer -type=Op
+
// Byte-code instruction set.
const (
// Instruction effect on stack: values consumed -- values produced.
- Nop = iota // --
- Add // n1 n2 -- sum ; sum = n1+n2
- Addr // a -- &a ;
- Assign // val -- ; mem[$1] = val
- Fassign // val -- ; mem[$1] = val
- Vassign // val dest -- ; dest.Set(val)
- Call // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = prog[f](a1, ...)
- Calli // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = prog[f](a1, ...)
- CallX // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = mem[f](a1, ...)
- Deref // x -- *x ;
- 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 // -- ;
- Field // s -- f ; f = s.FieldIndex($1, ...)
- Greater // n1 n2 -- cond; cond = n1 > n2
- Grow // -- ; sp += $1
- Index // a i -- a[i] ;
- Jump // -- ; ip += $1
- JumpTrue // cond -- ; if cond { ip += $1 }
- JumpFalse // cond -- ; if cond { ip += $1 }
- JumpSetTrue //
- JumpSetFalse //
- Lower // n1 n2 -- cond ; cond = n1 < n2
- Loweri // n1 -- cond ; cond = n1 < $1
- Mul // n1 n2 -- prod ; prod = n1*n2
- New // -- x; mem[fp+$1] = new mem[$2]
- Not // c -- r ; r = !c
- Pop // v --
- Push // -- v
- Return // [r1 .. ri] -- ; exit frame: sp = fp, fp = pop
- Sub // n1 n2 -- diff ; diff = n1 - n2
- Subi // n1 -- diff ; diff = n1 - $1
+ Nop Op = iota // --
+ Add // n1 n2 -- sum ; sum = n1+n2
+ Addr // a -- &a ;
+ Assign // val -- ; mem[$1] = val
+ Fassign // val -- ; mem[$1] = val
+ Vassign // val dest -- ; dest.Set(val)
+ Call // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = prog[f](a1, ...)
+ Calli // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = prog[f](a1, ...)
+ CallX // f [a1 .. ai] -- [r1 .. rj] ; r1, ... = mem[f](a1, ...)
+ Deref // x -- *x ;
+ 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 // -- ;
+ Field // s -- f ; f = s.FieldIndex($1, ...)
+ Greater // n1 n2 -- cond; cond = n1 > n2
+ Grow // -- ; sp += $1
+ Index // a i -- a[i] ;
+ Jump // -- ; ip += $1
+ JumpTrue // cond -- ; if cond { ip += $1 }
+ JumpFalse // cond -- ; if cond { ip += $1 }
+ JumpSetTrue //
+ JumpSetFalse //
+ Lower // n1 n2 -- cond ; cond = n1 < n2
+ Loweri // n1 -- cond ; cond = n1 < $1
+ Mul // n1 n2 -- prod ; prod = n1*n2
+ New // -- x; mem[fp+$1] = new mem[$2]
+ Not // c -- r ; r = !c
+ Pop // v --
+ Push // -- v
+ Return // [r1 .. ri] -- ; exit frame: sp = fp, fp = pop
+ Sub // n1 n2 -- diff ; diff = n1 - n2
+ Subi // n1 -- diff ; diff = n1 - $1
)
-var strop = [...]string{ // for VM tracing.
- Nop: "Nop",
- Add: "Add",
- Addr: "Addr",
- Assign: "Assign",
- Call: "Call",
- Calli: "Calli",
- CallX: "CallX",
- Deref: "Deref",
- Dup: "Dup",
- Equal: "Equal",
- EqualSet: "EqualSet",
- Exit: "Exit",
- Fassign: "Fassign",
- Fdup: "Fdup",
- Field: "Field",
- Greater: "Greater",
- Grow: "Grow",
- Index: "Index",
- Jump: "Jump",
- JumpTrue: "JumpTrue",
- JumpFalse: "JumpFalse",
- JumpSetTrue: "JumpSetTrue",
- JumpSetFalse: "JumpSetFalse",
- Lower: "Lower",
- Loweri: "Loweri",
- Mul: "Mul",
- New: "New",
- Not: "Not",
- Pop: "Pop",
- Push: "Push",
- Return: "Return",
- Sub: "Sub",
- Subi: "Subi",
- Vassign: "Vassign",
+// Instruction represents a virtual machine bytecode instruction.
+type Instruction struct {
+ Pos // position in source
+ Op // opcode
+ Arg []int // arguments
+}
+
+func (i Instruction) String() (s string) {
+ s = i.Op.String()
+ for _, a := range i.Arg {
+ s += fmt.Sprintf(" %v", a)
+ }
+ return s
}
// Code represents the virtual machine byte code.
-type Code [][]int64
+type Code []Instruction
// Machine represents a virtual machine.
type Machine struct {
code Code // code to execute
mem []Value // memory, as a stack
- ip, fp int // instruction and frame pointer
+ ip, fp int // instruction pointer and frame pointer
ic uint64 // instruction counter, incremented at each instruction executed
// flags uint // to set options such as restrict CallX, etc...
}
// Run runs a program.
func (m *Machine) Run() (err error) {
- code, mem, ip, fp, sp, ic := m.code, m.mem, m.ip, m.fp, 0, m.ic
+ mem, ip, fp, sp, ic := m.mem, m.ip, m.fp, 0, m.ic
defer func() { m.mem, m.ip, m.fp, m.ic = mem, ip, fp, ic }()
- trace := func() {
- if !debug {
- return
- }
- var op2, op3 string
- c := code[ip]
- if l := len(c); l > 2 {
- op2 = strconv.Itoa(int(c[2]))
- if l > 3 {
- op3 = strconv.Itoa(int(c[3]))
- }
- }
- log.Printf("ip:%-4d sp:%-4d fp:%-4d op:[%-12s %-4s %-4s] mem:%v\n", ip, sp, fp, strop[c[1]], op2, op3, Vstring(mem))
- }
-
for {
sp = len(mem) // stack pointer
- trace()
+ c := m.code[ip]
+ if debug {
+ log.Printf("ip:%-4d sp:%-4d fp:%-4d op:[%-14v] mem:%v\n", ip, sp, fp, c, Vstring(mem))
+ }
ic++
- switch op := code[ip]; op[1] {
+ switch c.Op {
case Add:
mem[sp-2] = ValueOf(int(mem[sp-2].Data.Int() + mem[sp-1].Data.Int()))
mem = mem[:sp-1]
@@ -134,10 +106,10 @@ func (m *Machine) Run() (err error) {
case Addr:
mem[sp-1].Data = mem[sp-1].Data.Addr()
case Assign:
- mem[op[2]].Data.Set(mem[sp-1].Data)
+ mem[c.Arg[0]].Data.Set(mem[sp-1].Data)
mem = mem[:sp-1]
case Fassign:
- mem[fp+int(op[2])-1].Data.Set(mem[sp-1].Data)
+ mem[fp+c.Arg[0]-1].Data.Set(mem[sp-1].Data)
mem = mem[:sp-1]
case Call:
nip := int(mem[sp-1].Data.Int())
@@ -148,25 +120,24 @@ func (m *Machine) Run() (err error) {
case Calli:
mem = append(mem, ValueOf(ip+1), ValueOf(fp))
fp = sp + 2
- ip = int(op[2])
+ ip = c.Arg[0]
continue
case CallX: // Should be made optional.
- l := int(op[2])
- in := make([]reflect.Value, l)
+ in := make([]reflect.Value, c.Arg[0])
for i := range in {
in[i] = mem[sp-2-i].Data
}
f := mem[sp-1].Data
- mem = mem[:sp-l-1]
+ mem = mem[:sp-c.Arg[0]-1]
for _, v := range f.Call(in) {
mem = append(mem, Value{Data: v})
}
case Deref:
mem[sp-1].Data = mem[sp-1].Data.Elem()
case Dup:
- mem = append(mem, mem[int(op[2])])
+ mem = append(mem, mem[c.Arg[0]])
case New:
- mem[int(op[2])+fp-1] = NewValue(mem[int(op[3])].Type)
+ mem[c.Arg[0]+fp-1] = NewValue(mem[c.Arg[1]].Type)
case Equal:
mem[sp-2] = ValueOf(mem[sp-2].Data.Equal(mem[sp-1].Data))
mem = mem[:sp-1]
@@ -183,44 +154,44 @@ func (m *Machine) Run() (err error) {
case Exit:
return err
case Fdup:
- mem = append(mem, mem[int(op[2])+fp-1])
+ mem = append(mem, mem[c.Arg[0]+fp-1])
case Field:
- fv := mem[sp-1].Data.FieldByIndex(slint(op[2:]))
+ fv := mem[sp-1].Data.FieldByIndex(c.Arg)
if !fv.CanSet() {
// Normally private fields can not bet set via reflect. Override this limitation.
fv = reflect.NewAt(fv.Type(), unsafe.Pointer(fv.UnsafeAddr())).Elem()
}
mem[sp-1].Data = fv
case Jump:
- ip += int(op[2])
+ ip += c.Arg[0]
continue
case JumpTrue:
cond := mem[sp-1].Data.Bool()
mem = mem[:sp-1]
if cond {
- ip += int(op[2])
+ ip += c.Arg[0]
continue
}
case JumpFalse:
cond := mem[sp-1].Data.Bool()
mem = mem[:sp-1]
if !cond {
- ip += int(op[2])
+ ip += c.Arg[0]
continue
}
case JumpSetTrue:
cond := mem[sp-1].Data.Bool()
if cond {
- ip += int(op[2])
- // Note that stack is not modified if cond is true
+ ip += c.Arg[0]
+ // Note that the stack is not modified if cond is true.
continue
}
mem = mem[:sp-1]
case JumpSetFalse:
cond := mem[sp-1].Data.Bool()
if !cond {
- ip += int(op[2])
- // Note that stack is not modified if cond is false
+ ip += c.Arg[0]
+ // Note that the stack is not modified if cond is false.
continue
}
mem = mem[:sp-1]
@@ -231,28 +202,27 @@ func (m *Machine) Run() (err error) {
mem[sp-2] = ValueOf(mem[sp-1].Data.Int() < mem[sp-2].Data.Int())
mem = mem[:sp-1]
case Loweri:
- mem[sp-1] = ValueOf(mem[sp-1].Data.Int() < op[2])
+ mem[sp-1] = ValueOf(mem[sp-1].Data.Int() < int64(c.Arg[0]))
case Not:
mem[sp-1] = ValueOf(!mem[sp-1].Data.Bool())
case Pop:
- mem = mem[:sp-int(op[2])]
+ mem = mem[:sp-c.Arg[0]]
case Push:
- // mem = append(mem, reflect.ValueOf(int(op[2])))
mem = append(mem, NewValue(TypeOf(0)))
- mem[sp].Data.SetInt(op[2])
+ mem[sp].Data.SetInt(int64(c.Arg[0]))
case Grow:
- mem = append(mem, make([]Value, op[2])...)
+ mem = append(mem, make([]Value, c.Arg[0])...)
case Return:
ip = int(mem[fp-2].Data.Int())
ofp := fp
fp = int(mem[fp-1].Data.Int())
- mem = append(mem[:ofp-int(op[2])-int(op[3])-1], mem[sp-int(op[2]):]...)
+ mem = append(mem[:ofp-c.Arg[0]-c.Arg[1]-1], mem[sp-c.Arg[0]:]...)
continue
case Sub:
mem[sp-2] = ValueOf(int(mem[sp-1].Data.Int() - mem[sp-2].Data.Int()))
mem = mem[:sp-1]
case Subi:
- mem[sp-1] = ValueOf(int(mem[sp-1].Data.Int() - op[2]))
+ mem[sp-1] = ValueOf(int(mem[sp-1].Data.Int()) - c.Arg[0])
case Index:
mem[sp-2].Data = mem[sp-1].Data.Index(int(mem[sp-2].Data.Int()))
mem = mem[:sp-1]
@@ -265,7 +235,7 @@ func (m *Machine) Run() (err error) {
}
// PushCode adds instructions to the machine code.
-func (m *Machine) PushCode(code ...[]int64) (p int) {
+func (m *Machine) PushCode(code ...Instruction) (p int) {
p = len(m.code)
m.code = append(m.code, code...)
return p
@@ -282,12 +252,12 @@ func (m *Machine) Push(v ...Value) (l int) {
}
// Pop removes and returns the value on the top of machine stack.
-func (m *Machine) Pop() (v Value) {
- l := len(m.mem) - 1
- v = m.mem[l]
- m.mem = m.mem[:l]
- return v
-}
+// func (m *Machine) Pop() (v Value) {
+// l := len(m.mem) - 1
+// v = m.mem[l]
+// m.mem = m.mem[:l]
+// return v
+// }
// Top returns (but not remove) the value on the top of machine stack.
func (m *Machine) Top() (v Value) {
@@ -299,40 +269,11 @@ func (m *Machine) Top() (v Value) {
// PopExit removes the last machine code instruction if is Exit.
func (m *Machine) PopExit() {
- if l := len(m.code); l > 0 && m.code[l-1][1] == Exit {
+ if l := len(m.code); l > 0 && m.code[l-1].Op == Exit {
m.code = m.code[:l-1]
}
}
-// CodeString returns the string representation of a machine code instruction.
-func CodeString(op []int64) string {
- switch len(op) {
- case 2:
- return strop[op[1]]
- case 3:
- return fmt.Sprintf("%s %d", strop[op[1]], op[2])
- case 4:
- return fmt.Sprintf("%s %d %d", strop[op[1]], op[2], op[3])
- }
- return ""
-}
-
-// Disassemble returns the code as a readable string.
-func Disassemble(code [][]int64) (asm string) {
- for _, op := range code {
- asm += CodeString(op) + "\n"
- }
- return asm
-}
-
-func slint(a []int64) []int {
- r := make([]int, len(a))
- for i, v := range a {
- r[i] = int(v)
- }
- return r
-}
-
// Vstring returns the string repreentation of a list of values.
func Vstring(lv []Value) string {
s := "["
diff --git a/vm/vm_test.go b/vm/vm_test.go
index 43333ad..f7cbfbf 100644
--- a/vm/vm_test.go
+++ b/vm/vm_test.go
@@ -50,189 +50,189 @@ func BenchmarkVM(b *testing.B) {
}
var tests = []struct {
- sym []Value // initial memory values
- code [][]int64 // bytecode to execute
- start, end int //
- mem string // expected memory content
+ sym []Value // initial memory values
+ code []Instruction // bytecode to execute
+ start, end int //
+ mem string // expected memory content
}{{ // #00 -- A simple addition.
- code: [][]int64{
- {0, Push, 1},
- {0, Push, 2},
- {0, Add},
- {0, Exit},
+ code: []Instruction{
+ {Op: Push, Arg: []int{1}},
+ {Op: Push, Arg: []int{2}},
+ {Op: Add},
+ {Op: Exit},
},
start: 0, end: 1, mem: "[3]",
}, { // #01 -- A simple subtraction.
- code: [][]int64{
- {0, Push, 2},
- {0, Push, 3},
- {0, Sub},
- {0, Exit},
+ code: []Instruction{
+ {Op: Push, Arg: []int{2}},
+ {Op: Push, Arg: []int{3}},
+ {Op: Sub},
+ {Op: Exit},
},
start: 0, end: 1, mem: "[1]",
}, { // #02 -- A simple multiplication.
- code: [][]int64{
- {0, Push, 3},
- {0, Push, 2},
- {0, Mul},
- {0, Exit},
+ code: []Instruction{
+ {Op: Push, Arg: []int{3}},
+ {Op: Push, Arg: []int{2}},
+ {Op: Mul},
+ {Op: Exit},
},
start: 0, end: 1, mem: "[6]",
}, { // #03 -- lower.
- code: [][]int64{
- {0, Push, 3},
- {0, Push, 2},
- {0, Lower},
- {0, Exit},
+ code: []Instruction{
+ {Op: Push, Arg: []int{3}},
+ {Op: Push, Arg: []int{2}},
+ {Op: Lower},
+ {Op: Exit},
},
start: 0, end: 1, mem: "[true]",
}, { // #04 -- greater.
- code: [][]int64{
- {0, Push, 2},
- {0, Push, 3},
- {0, Greater},
- {0, Exit},
+ code: []Instruction{
+ {Op: Push, Arg: []int{2}},
+ {Op: Push, Arg: []int{3}},
+ {Op: Greater},
+ {Op: Exit},
},
start: 0, end: 1, mem: "[true]",
}, { // #05 -- equal.
- code: [][]int64{
- {0, Push, 2},
- {0, Push, 3},
- {0, Equal},
- {0, Exit},
+ code: []Instruction{
+ {Op: Push, Arg: []int{2}},
+ {Op: Push, Arg: []int{3}},
+ {Op: Equal},
+ {Op: Exit},
},
start: 0, end: 1, mem: "[false]",
}, { // #06 -- equalSet.
- code: [][]int64{
- {0, Push, 2},
- {0, Push, 3},
- {0, EqualSet},
- {0, Exit},
+ code: []Instruction{
+ {Op: Push, Arg: []int{2}},
+ {Op: Push, Arg: []int{3}},
+ {Op: EqualSet},
+ {Op: Exit},
},
start: 0, end: 2, mem: "[2 false]",
}, { // #07 -- equalSet.
- code: [][]int64{
- {0, Push, 3},
- {0, Push, 3},
- {0, EqualSet},
- {0, Exit},
+ code: []Instruction{
+ {Op: Push, Arg: []int{3}},
+ {Op: Push, Arg: []int{3}},
+ {Op: EqualSet},
+ {Op: Exit},
},
start: 0, end: 1, mem: "[true]",
}, { // #08 not.
- code: [][]int64{
- {0, Push, 3},
- {0, Push, 3},
- {0, Equal},
- {0, Not},
- {0, Exit},
+ code: []Instruction{
+ {Op: Push, Arg: []int{3}},
+ {Op: Push, Arg: []int{3}},
+ {Op: Equal},
+ {Op: Not},
+ {Op: Exit},
},
start: 0, end: 1, mem: "[false]",
}, { // #09 pop.
- code: [][]int64{
- {0, Push, 3},
- {0, Push, 2},
- {0, Pop, 1},
- {0, Exit},
+ code: []Instruction{
+ {Op: Push, Arg: []int{3}},
+ {Op: Push, Arg: []int{2}},
+ {Op: Pop, Arg: []int{1}},
+ {Op: Exit},
},
start: 0, end: 1, mem: "[3]",
}, { // #10 -- Assign a variable.
sym: []Value{{Type: TypeOf(0), Data: reflect.ValueOf(0)}},
- code: [][]int64{
- {0, Grow, 1},
- {0, New, 2, 0},
- {0, Push, 2},
- {0, Assign, 1},
- {0, Exit},
+ code: []Instruction{
+ {Op: Grow, Arg: []int{1}},
+ {Op: New, Arg: []int{2, 0}},
+ {Op: Push, Arg: []int{2}},
+ {Op: Assign, Arg: []int{1}},
+ {Op: Exit},
},
start: 1, end: 2, mem: "[2]",
}, { // #11 -- Calling a function defined outside the VM.
sym: []Value{ValueOf(fmt.Println), ValueOf("Hello")},
- code: [][]int64{
- {0, Dup, 0},
- {0, CallX, 1},
- {0, Exit},
+ code: []Instruction{
+ {Op: Dup, Arg: []int{0}},
+ {Op: CallX, Arg: []int{1}},
+ {Op: Exit},
},
start: 1, end: 3, mem: "[6 <nil>]",
}, { // #12 -- Defining and calling a function in VM.
- code: [][]int64{
- {0, Jump, 3}, // 0
- {0, Push, 3}, // 1
- {0, Return, 1, 1}, // 2
- {0, Push, 1}, // 3
- {0, Calli, 1}, // 4
- {0, Exit}, // 5
+ code: []Instruction{
+ {Op: Jump, Arg: []int{3}}, // 0
+ {Op: Push, Arg: []int{3}}, // 1
+ {Op: Return, Arg: []int{1, 1}}, // 2
+ {Op: Push, Arg: []int{1}}, // 3
+ {Op: Calli, Arg: []int{1}}, // 4
+ {Op: Exit}, // 5
},
start: 0, end: 1, mem: "[3]",
}, { // #13 -- Defining and calling a function in VM.
- code: [][]int64{
- {0, Jump, 3}, // 0
- {0, Push, 3}, // 1
- {0, Return, 1, 1}, // 2
- {0, Push, 1}, // 3
- {0, Push, 1}, // 4
- {0, Call}, // 5
- {0, Exit}, // 6
+ code: []Instruction{
+ {Op: Jump, Arg: []int{3}}, // 0
+ {Op: Push, Arg: []int{3}}, // 1
+ {Op: Return, Arg: []int{1, 1}}, // 2
+ {Op: Push, Arg: []int{1}}, // 3
+ {Op: Push, Arg: []int{1}}, // 4
+ {Op: Call}, // 5
+ {Op: Exit}, // 6
},
start: 0, end: 1, mem: "[3]",
}, { // #14 -- Defining and calling a function in VM.
- code: [][]int64{
- {0, Jump, 5}, // 0
- {0, Push, 3}, // 1
- {0, Fassign, -2}, // 2
- {0, Fdup, -2}, // 3
- {0, Return, 1, 1}, // 4
- {0, Push, 1}, // 5
- {0, Push, 1}, // 6
- {0, Call}, // 7
- {0, Exit}, // 8
+ code: []Instruction{
+ {Op: Jump, Arg: []int{5}}, // 0
+ {Op: Push, Arg: []int{3}}, // 1
+ {Op: Fassign, Arg: []int{-2}}, // 2
+ {Op: Fdup, Arg: []int{-2}}, // 3
+ {Op: Return, Arg: []int{1, 1}}, // 4
+ {Op: Push, Arg: []int{1}}, // 5
+ {Op: Push, Arg: []int{1}}, // 6
+ {Op: Call}, // 7
+ {Op: Exit}, // 8
},
start: 0, end: 1, mem: "[3]",
}, { // #15 -- Fibonacci numbers, hand written. Showcase recursivity.
- code: [][]int64{
- {0, Jump, 19}, // 0
- {0, Push, 2}, // 2 [2]
- {0, Fdup, -2}, // 1 [2 i]
- {0, Lower}, // 3 [true/false]
- {0, JumpTrue, 13}, // 4 [], goto 17
- {0, Push, 2}, // 5 [i 2]
- {0, Fdup, -2}, // 6 [i]
- {0, Sub}, // 7 [(i-2)]
- {0, Push, 1}, // 8
- {0, Call}, // 9 [fib(i-2)]
- {0, Push, 1}, // 10 [(i-2) i 1]
- {0, Fdup, -2}, // 11 [fib(i-2) i]
- {0, Sub}, // 12 [(i-2) (i-1)]
- {0, Push, 1}, // 13
- {0, Call}, // 14 [fib(i-2) fib(i-1)]
- {0, Add}, // 15 [fib(i-2)+fib(i-1)]
- {0, Return, 1, 1}, // 16 return i
- {0, Fdup, -2}, // 17 [i]
- {0, Return, 1, 1}, // 18 return i
- {0, Push, 6}, // 19 [1]
- {0, Push, 1}, // 20
- {0, Call}, // 21 [fib(*1)]
- {0, Exit}, // 22
+ code: []Instruction{
+ {Op: Jump, Arg: []int{19}}, // 0
+ {Op: Push, Arg: []int{2}}, // 2 [2]
+ {Op: Fdup, Arg: []int{-2}}, // 1 [2 i]
+ {Op: Lower}, // 3 [true/false]
+ {Op: JumpTrue, Arg: []int{13}}, // 4 [], goto 17
+ {Op: Push, Arg: []int{2}}, // 5 [i 2]
+ {Op: Fdup, Arg: []int{-2}}, // 6 [i]
+ {Op: Sub}, // 7 [(i-2)]
+ {Op: Push, Arg: []int{1}}, // 8
+ {Op: Call}, // 9 [fib(i-2)]
+ {Op: Push, Arg: []int{1}}, // 10 [(i-2) i 1]
+ {Op: Fdup, Arg: []int{-2}}, // 11 [fib(i-2) i]
+ {Op: Sub}, // 12 [(i-2) (i-1)]
+ {Op: Push, Arg: []int{1}}, // 13
+ {Op: Call}, // 14 [fib(i-2) fib(i-1)]
+ {Op: Add}, // 15 [fib(i-2)+fib(i-1)]
+ {Op: Return, Arg: []int{1, 1}}, // 16 return i
+ {Op: Fdup, Arg: []int{-2}}, // 17 [i]
+ {Op: Return, Arg: []int{1, 1}}, // 18 return i
+ {Op: Push, Arg: []int{6}}, // 19 [1]
+ {Op: Push, Arg: []int{1}}, // 20
+ {Op: Call}, // 21 [fib(*1)]
+ {Op: Exit}, // 22
},
start: 0, end: 1, mem: "[8]",
}, { // #16 -- Fibonacci with some immediate instructions.
- code: [][]int64{
- {0, Jump, 14}, // 0
- {0, Fdup, -2}, // 1 [i]
- {0, Loweri, 2}, // 2 [true/false]
- {0, JumpTrue, 9}, // 3 [], goto 12
- {0, Fdup, -2}, // 4 [i]
- {0, Subi, 2}, // 5 [(i-2)]
- {0, Calli, 1}, // 6 [fib(i-2)]
- {0, Fdup, -2}, // 7 [fib(i-2) i]
- {0, Subi, 1}, // 8 [(i-2) (i-1)]
- {0, Calli, 1}, // 9 [fib(i-2) fib(i-1)], call 1
- {0, Add}, // 10 [fib(i-2)+fib(i-1)]
- {0, Return, 1, 1}, // 11 return i
- {0, Fdup, -2}, // 12 [i]
- {0, Return, 1, 1}, // 13 return i
- {0, Push, 6}, // 14 [1]
- {0, Calli, 1}, // 15 [fib(*1)], call 1
- {0, Exit}, // 16
+ code: []Instruction{
+ {Op: Jump, Arg: []int{14}}, // 0
+ {Op: Fdup, Arg: []int{-2}}, // 1 [i]
+ {Op: Loweri, Arg: []int{2}}, // 2 [true/false]
+ {Op: JumpTrue, Arg: []int{9}}, // 3 [], goto 12
+ {Op: Fdup, Arg: []int{-2}}, // 4 [i]
+ {Op: Subi, Arg: []int{2}}, // 5 [(i-2)]
+ {Op: Calli, Arg: []int{1}}, // 6 [fib(i-2)]
+ {Op: Fdup, Arg: []int{-2}}, // 7 [fib(i-2) i]
+ {Op: Subi, Arg: []int{1}}, // 8 [(i-2) (i-1)]
+ {Op: Calli, Arg: []int{1}}, // 9 [fib(i-2) fib(i-1)], call 1
+ {Op: Add}, // 10 [fib(i-2)+fib(i-1)]
+ {Op: Return, Arg: []int{1, 1}}, // 11 return i
+ {Op: Fdup, Arg: []int{-2}}, // 12 [i]
+ {Op: Return, Arg: []int{1, 1}}, // 13 return i
+ {Op: Push, Arg: []int{6}}, // 14 [1]
+ {Op: Calli, Arg: []int{1}}, // 15 [fib(*1)], call 1
+ {Op: Exit}, // 16
},
start: 0, end: 1, mem: "[8]",
}}