summaryrefslogtreecommitdiff
path: root/vm1/vm_test.go
blob: 1268bba68081d67b733a2162cd94d3579357b071 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package vm1

import (
	"fmt"
	"testing"
)

func TestVM(t *testing.T) {
	for _, test := range tests {
		t.Run("", func(t *testing.T) {
			m := &Machine{}
			for _, v := range test.sym {
				m.Push(v)
			}
			m.PushCode(test.code)
			m.Run()
			t.Log(m.mem)
			r := fmt.Sprintf("%v", m.mem[test.start:test.end])
			if r != test.mem {
				t.Errorf("got %v, want %v", r, test.mem)
			}
		})
	}
}

func BenchmarkVM(b *testing.B) {
	for _, test := range tests {
		b.Run("", func(b *testing.B) {
			for i := 0; i < b.N; i++ {
				b.StopTimer()
				m := &Machine{}
				m.PushCode(test.code)
				b.StartTimer()

				m.Run()
			}
		})
	}
}

var tests = []struct {
	sym        []any     // initial memory values
	code       [][]int64 // 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},
	},
	start: 0, end: 1, mem: "[3]",
}, { // #01 -- Calling a function defined outside the VM.
	sym: []any{fmt.Println, "Hello"},
	code: [][]int64{
		{0, CallX, 1},
		{0, Exit},
	},
	start: 0, end: 2, mem: "[6 <nil>]",
}, { // #02 -- Defining and calling a function in VM.
	code: [][]int64{
		{0, Jump, 4},   // 0
		{0, Enter},     // 1
		{0, Push, 3},   // 2
		{0, Return, 1}, // 3
		{0, Push, 1},   // 4
		{0, Call, -4},  // 5
		{0, Exit},      // 6
	},
	start: 0, end: 1, mem: "[3]",
}, { // #03 -- Fibonacci numbers, hand written. Showcase recursivity.
	code: [][]int64{
		{0, Jump, 18},     // 0, goto 18
		{0, Enter},        // 1,
		{0, Fdup, -2},     // 2, [i]
		{0, Push, 2},      // 3, [i 2]
		{0, Lower},        // 4, [true/false]
		{0, JumpTrue, 11}, // 5, [], goto 16
		{0, Fdup, -2},     // 6  [i]
		{0, Push, 2},      // 7  [i 2]
		{0, Sub},          // 8  [(i-2)]
		{0, Call, -8},     // 9  [fib(i-2)]
		{0, Fdup, -2},     // 10 [fib(i-2) i]
		{0, Push, 1},      // 11 [(i-2) i 1]
		{0, Sub},          // 12 [(i-2) (i-1)]
		{0, Call, -12},    // 13 [fib(i-2) fib(i-1)]
		{0, Add},          // 14 [fib(i-2)+fib(i-1)]
		{0, Return, 1},    // 15 return i
		{0, Fdup, -2},     // 16 [i]
		{0, Return, 1},    // 17 return i
		{0, Push, 6},      // 18 [1]
		{0, Call, -18},    // 19 [fib(*1)]
		{0, Exit},         // 20
	},
	start: 0, end: 1, mem: "[8]",
}, { // #04 -- Fibonacci with some immediate instructions.
	code: [][]int64{
		{0, Jump, 15},    // 0, goto 15
		{0, Enter},       // 1,
		{0, Fdup, -2},    // 2, [i]
		{0, Loweri, 2},   // 3, [true/false]
		{0, JumpTrue, 9}, // 4, [], goto 13
		{0, Fdup, -2},    // 5  [i]
		{0, Subi, 2},     // 6  [(i-2)]
		{0, Call, -6},    // 7  [fib(i-2)]
		{0, Fdup, -2},    // 8  [fib(i-2) i]
		{0, Subi, 1},     // 9  [(i-2) (i-1)]
		{0, Call, -9},    // 10 [fib(i-2) fib(i-1)], call 1
		{0, Add},         // 11 [fib(i-2)+fib(i-1)]
		{0, Return, 1},   // 12 return i
		{0, Fdup, -2},    // 13 [i]
		{0, Return, 1},   // 14 return i
		{0, Push, 6},     // 15 [1]
		{0, Call, -15},   // 16 [fib(*1)], call 1
		{0, Exit},        // 17
	},
	start: 0, end: 1, mem: "[8]",
}}