-
Notifications
You must be signed in to change notification settings - Fork 0
/
vm.sc
158 lines (139 loc) · 3.67 KB
/
vm.sc
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using import Array
using import Map
using import String
using import struct
using import .common
import .utils
import .stdlib
fn step (vm)
let stack program =
vm.stack
vm.program
let reg = vm.registers
let acc pc =
reg.acc
reg.pc
inline calc-index (i)
(countof stack) - 1 - i
inline numeric-bin-op (op a b)
let a b =
stack @ (calc-index a)
stack @ (calc-index b)
op
utils.extract-as-tag a 'Number
utils.extract-as-tag b 'Number
inline logic-bin-op (op a b)
let a b =
stack @ (calc-index a)
stack @ (calc-index b)
op
imply a bool
imply b bool
inline jump (idx)
pc = idx
dispatch ('fetch vm)
case CALL (argc)
let f = ('pop stack)
# ...
case CCALL (argc)
let name = (utils.extract-as-tag ('pop stack) 'String)
try
('get program.functions name) stack
else
print name
error "unknown C function"
;
case PUSH (address)
'append stack (copy (program.constant-table @ address))
case PUSHI (index)
'append stack (copy (stack @ (calc-index index)))
case DISCARD (argc)
for i in (range argc)
'pop stack
;
case ALLOCA (argc)
for i in (range argc)
'append stack (LangValue.Nil)
# arithmetic
case ADD (A B)
acc = (numeric-bin-op fadd A B)
case SUB (A B)
acc = (numeric-bin-op fsub A B)
case MUL (A B)
acc = (numeric-bin-op fmul A B)
case DIV (A B)
acc = (numeric-bin-op fdiv A B)
case STORE (index)
stack @ (calc-index index) = (LangValue.Number acc)
# control flow
case JUMP (address)
jump address
case JUMP_T (address)
let tval = ('pop stack)
if tval
jump address
case JUMP_F (address)
let tval = ('pop stack)
if (not tval)
jump address
# comparisons
case TEST_EQ (A B)
# for equality, we let the Enum == metamethod do the work.
let A B =
stack @ (calc-index A)
stack @ (calc-index B)
'append stack (LangValue.Boolean (A == B))
case TEST_NEQ (A B)
# see TEST_EQ
let A B =
stack @ (calc-index A)
stack @ (calc-index B)
'append stack (LangValue.Boolean (A != B))
case TEST_GT (A B)
'append stack
LangValue.Boolean
numeric-bin-op fcmp>o A B
case TEST_LT (A B)
'append stack
LangValue.Boolean
numeric-bin-op fcmp<o A B
# logical operators
case NOT (arg)
'append stack
LangValue.Boolean
not (stack @ (calc-index arg))
case AND (A B)
'append stack
LangValue.Boolean
logic-bin-op band A B
case OR (A B)
'append stack
LangValue.Boolean
logic-bin-op bor A B
default
error "unsupported opcode"
struct Registers
acc : f64
pc : usize
struct VM
program : Program
stack : (Array LangValue)
registers : Registers
inline __typecall (cls program)
local program = program
stdlib.register program
super-type.__typecall cls
program = program
inline done? (self)
self.registers.pc >= (countof self.program.code)
inline fetch (self)
op := self.program.code @ self.registers.pc
self.registers.pc += 1
op
let step
inline execute (self)
while (not ('done? self))
step self
do
let VM
locals;