1use core::fmt;
2pub type Register = u8;
3pub type ConstIndex = u16;
4pub type JumpOffset = i16;
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub enum Instruction {
7 LoadNil(Register),
8 LoadBool(Register, bool),
9 LoadConst(Register, ConstIndex),
10 LoadGlobal(Register, ConstIndex),
11 StoreGlobal(ConstIndex, Register),
12 Move(Register, Register),
13 Add(Register, Register, Register),
14 Sub(Register, Register, Register),
15 Mul(Register, Register, Register),
16 Div(Register, Register, Register),
17 Mod(Register, Register, Register),
18 Neg(Register, Register),
19 Eq(Register, Register, Register),
20 Ne(Register, Register, Register),
21 Lt(Register, Register, Register),
22 Le(Register, Register, Register),
23 Gt(Register, Register, Register),
24 Ge(Register, Register, Register),
25 And(Register, Register, Register),
26 Or(Register, Register, Register),
27 Not(Register, Register),
28 Jump(JumpOffset),
29 JumpIf(Register, JumpOffset),
30 JumpIfNot(Register, JumpOffset),
31 Call(Register, Register, u8, Register),
32 Return(Register),
33 NewArray(Register, Register, u8),
34 NewMap(Register),
35 NewStruct(Register, ConstIndex, ConstIndex, Register, u8),
36 NewEnumUnit(Register, ConstIndex, ConstIndex),
37 NewEnumVariant(Register, ConstIndex, ConstIndex, Register, u8),
38 TupleNew(Register, Register, u8),
39 TupleGet(Register, Register, u8),
40 IsEnumVariant(Register, Register, ConstIndex, ConstIndex),
41 GetEnumValue(Register, Register, u8),
42 GetField(Register, Register, ConstIndex),
43 SetField(Register, ConstIndex, Register),
44 GetIndex(Register, Register, Register),
45 ArrayLen(Register, Register),
46 SetIndex(Register, Register, Register),
47 Concat(Register, Register, Register),
48 CallMethod(Register, ConstIndex, Register, u8, Register),
49 TypeIs(Register, Register, ConstIndex),
50 LoadUpvalue(Register, u8),
51 StoreUpvalue(u8, Register),
52 Closure(Register, ConstIndex, Register, u8),
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum OpCode {
57 LoadNil,
58 LoadBool,
59 LoadConst,
60 LoadGlobal,
61 StoreGlobal,
62 Move,
63 Add,
64 Sub,
65 Mul,
66 Div,
67 Mod,
68 Neg,
69 Eq,
70 Ne,
71 Lt,
72 Le,
73 Gt,
74 Ge,
75 And,
76 Or,
77 Not,
78 Jump,
79 JumpIf,
80 JumpIfNot,
81 Call,
82 Return,
83 NewArray,
84 NewMap,
85 NewStruct,
86 NewEnumUnit,
87 NewEnumVariant,
88 TupleNew,
89 TupleGet,
90 IsEnumVariant,
91 GetEnumValue,
92 GetField,
93 SetField,
94 GetIndex,
95 ArrayLen,
96 SetIndex,
97 Concat,
98 CallMethod,
99 TypeIs,
100 LoadUpvalue,
101 StoreUpvalue,
102 Closure,
103}
104
105impl Instruction {
106 pub fn opcode(&self) -> OpCode {
107 match self {
108 Instruction::LoadNil(_) => OpCode::LoadNil,
109 Instruction::LoadBool(_, _) => OpCode::LoadBool,
110 Instruction::LoadConst(_, _) => OpCode::LoadConst,
111 Instruction::LoadGlobal(_, _) => OpCode::LoadGlobal,
112 Instruction::StoreGlobal(_, _) => OpCode::StoreGlobal,
113 Instruction::Move(_, _) => OpCode::Move,
114 Instruction::Add(_, _, _) => OpCode::Add,
115 Instruction::Sub(_, _, _) => OpCode::Sub,
116 Instruction::Mul(_, _, _) => OpCode::Mul,
117 Instruction::Div(_, _, _) => OpCode::Div,
118 Instruction::Mod(_, _, _) => OpCode::Mod,
119 Instruction::Neg(_, _) => OpCode::Neg,
120 Instruction::Eq(_, _, _) => OpCode::Eq,
121 Instruction::Ne(_, _, _) => OpCode::Ne,
122 Instruction::Lt(_, _, _) => OpCode::Lt,
123 Instruction::Le(_, _, _) => OpCode::Le,
124 Instruction::Gt(_, _, _) => OpCode::Gt,
125 Instruction::Ge(_, _, _) => OpCode::Ge,
126 Instruction::And(_, _, _) => OpCode::And,
127 Instruction::Or(_, _, _) => OpCode::Or,
128 Instruction::Not(_, _) => OpCode::Not,
129 Instruction::Jump(_) => OpCode::Jump,
130 Instruction::JumpIf(_, _) => OpCode::JumpIf,
131 Instruction::JumpIfNot(_, _) => OpCode::JumpIfNot,
132 Instruction::Call(_, _, _, _) => OpCode::Call,
133 Instruction::Return(_) => OpCode::Return,
134 Instruction::NewArray(_, _, _) => OpCode::NewArray,
135 Instruction::NewMap(_) => OpCode::NewMap,
136 Instruction::NewStruct(_, _, _, _, _) => OpCode::NewStruct,
137 Instruction::NewEnumUnit(_, _, _) => OpCode::NewEnumUnit,
138 Instruction::NewEnumVariant(_, _, _, _, _) => OpCode::NewEnumVariant,
139 Instruction::TupleNew(_, _, _) => OpCode::TupleNew,
140 Instruction::TupleGet(_, _, _) => OpCode::TupleGet,
141 Instruction::IsEnumVariant(_, _, _, _) => OpCode::IsEnumVariant,
142 Instruction::GetEnumValue(_, _, _) => OpCode::GetEnumValue,
143 Instruction::GetField(_, _, _) => OpCode::GetField,
144 Instruction::SetField(_, _, _) => OpCode::SetField,
145 Instruction::GetIndex(_, _, _) => OpCode::GetIndex,
146 Instruction::ArrayLen(_, _) => OpCode::ArrayLen,
147 Instruction::SetIndex(_, _, _) => OpCode::SetIndex,
148 Instruction::Concat(_, _, _) => OpCode::Concat,
149 Instruction::CallMethod(_, _, _, _, _) => OpCode::CallMethod,
150 Instruction::TypeIs(_, _, _) => OpCode::TypeIs,
151 Instruction::LoadUpvalue(_, _) => OpCode::LoadUpvalue,
152 Instruction::StoreUpvalue(_, _) => OpCode::StoreUpvalue,
153 Instruction::Closure(_, _, _, _) => OpCode::Closure,
154 }
155 }
156}
157
158impl fmt::Display for Instruction {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 match self {
161 Instruction::LoadNil(r) => write!(f, "LoadNil R{}", r),
162 Instruction::LoadBool(r, b) => write!(f, "LoadBool R{}, {}", r, b),
163 Instruction::LoadConst(r, c) => write!(f, "LoadConst R{}, K{}", r, c),
164 Instruction::LoadGlobal(r, c) => write!(f, "LoadGlobal R{}, K{}", r, c),
165 Instruction::StoreGlobal(c, r) => write!(f, "StoreGlobal K{}, R{}", c, r),
166 Instruction::Move(d, s) => write!(f, "Move R{}, R{}", d, s),
167 Instruction::Add(d, l, r) => write!(f, "Add R{}, R{}, R{}", d, l, r),
168 Instruction::Sub(d, l, r) => write!(f, "Sub R{}, R{}, R{}", d, l, r),
169 Instruction::Mul(d, l, r) => write!(f, "Mul R{}, R{}, R{}", d, l, r),
170 Instruction::Div(d, l, r) => write!(f, "Div R{}, R{}, R{}", d, l, r),
171 Instruction::Mod(d, l, r) => write!(f, "Mod R{}, R{}, R{}", d, l, r),
172 Instruction::Neg(d, s) => write!(f, "Neg R{}, R{}", d, s),
173 Instruction::Eq(d, l, r) => write!(f, "Eq R{}, R{}, R{}", d, l, r),
174 Instruction::Ne(d, l, r) => write!(f, "Ne R{}, R{}, R{}", d, l, r),
175 Instruction::Lt(d, l, r) => write!(f, "Lt R{}, R{}, R{}", d, l, r),
176 Instruction::Le(d, l, r) => write!(f, "Le R{}, R{}, R{}", d, l, r),
177 Instruction::Gt(d, l, r) => write!(f, "Gt R{}, R{}, R{}", d, l, r),
178 Instruction::Ge(d, l, r) => write!(f, "Ge R{}, R{}, R{}", d, l, r),
179 Instruction::And(d, l, r) => write!(f, "And R{}, R{}, R{}", d, l, r),
180 Instruction::Or(d, l, r) => write!(f, "Or R{}, R{}, R{}", d, l, r),
181 Instruction::Not(d, s) => write!(f, "Not R{}, R{}", d, s),
182 Instruction::Jump(offset) => write!(f, "Jump {}", offset),
183 Instruction::JumpIf(r, offset) => write!(f, "JumpIf R{}, {}", r, offset),
184 Instruction::JumpIfNot(r, offset) => write!(f, "JumpIfNot R{}, {}", r, offset),
185 Instruction::Call(func, args, cnt, dest) => {
186 if *cnt == 0 {
187 write!(f, "Call R{}, <no args>, R{}", func, dest)
188 } else {
189 let arg_start = *args as usize;
190 let arg_end = arg_start + (*cnt as usize) - 1;
191 write!(f, "Call R{}, R{}..R{}, R{}", func, args, arg_end, dest)
192 }
193 }
194
195 Instruction::Return(r) => write!(f, "Return R{}", r),
196 Instruction::NewArray(d, elems, cnt) => {
197 if *cnt == 0 {
198 write!(f, "NewArray R{}, <no elements>", d)
199 } else {
200 let end = (*elems as usize) + (*cnt as usize) - 1;
201 write!(f, "NewArray R{}, R{}..R{}", d, elems, end)
202 }
203 }
204
205 Instruction::NewMap(r) => write!(f, "NewMap R{}", r),
206 Instruction::NewStruct(d, name, field_names, fields, cnt) => {
207 if *cnt == 0 {
208 write!(
209 f,
210 "NewStruct R{}, K{}, <no fields>, R{}..R{}",
211 d, name, fields, fields
212 )
213 } else {
214 let field_name_start = *field_names as usize;
215 let field_name_end = field_name_start + (*cnt as usize) - 1;
216 let value_start = *fields as usize;
217 let value_end = value_start + (*cnt as usize) - 1;
218 write!(
219 f,
220 "NewStruct R{}, K{}, K{}..K{}, R{}..R{}",
221 d, name, field_names, field_name_end, fields, value_end
222 )
223 }
224 }
225
226 Instruction::NewEnumUnit(d, enum_name, variant) => {
227 write!(f, "NewEnumUnit R{}, K{}, K{}", d, enum_name, variant)
228 }
229
230 Instruction::NewEnumVariant(d, enum_name, variant, values, cnt) => {
231 if *cnt == 0 {
232 write!(
233 f,
234 "NewEnumVariant R{}, K{}, K{}, <no values>",
235 d, enum_name, variant
236 )
237 } else {
238 let value_start = *values as usize;
239 let value_end = value_start + (*cnt as usize) - 1;
240 write!(
241 f,
242 "NewEnumVariant R{}, K{}, K{}, R{}..R{}",
243 d, enum_name, variant, values, value_end
244 )
245 }
246 }
247
248 Instruction::TupleNew(d, first, cnt) => {
249 if *cnt == 0 {
250 write!(f, "TupleNew R{}, <empty>", d)
251 } else {
252 let start = *first as usize;
253 let end = start + (*cnt as usize) - 1;
254 write!(f, "TupleNew R{}, R{}..R{}", d, first, end)
255 }
256 }
257
258 Instruction::TupleGet(d, tuple, idx) => {
259 write!(f, "TupleGet R{}, R{}, {}", d, tuple, idx)
260 }
261
262 Instruction::IsEnumVariant(d, val, enum_name, variant) => {
263 write!(
264 f,
265 "IsEnumVariant R{}, R{}, K{}, K{}",
266 d, val, enum_name, variant
267 )
268 }
269
270 Instruction::GetEnumValue(d, enum_reg, idx) => {
271 write!(f, "GetEnumValue R{}, R{}, {}", d, enum_reg, idx)
272 }
273
274 Instruction::GetField(d, obj, field) => {
275 write!(f, "GetField R{}, R{}, K{}", d, obj, field)
276 }
277
278 Instruction::SetField(obj, field, val) => {
279 write!(f, "SetField R{}, K{}, R{}", obj, field, val)
280 }
281
282 Instruction::GetIndex(d, arr, idx) => write!(f, "GetIndex R{}, R{}, R{}", d, arr, idx),
283 Instruction::ArrayLen(d, arr) => write!(f, "ArrayLen R{}, R{}", d, arr),
284 Instruction::SetIndex(arr, idx, val) => {
285 write!(f, "SetIndex R{}, R{}, R{}", arr, idx, val)
286 }
287
288 Instruction::Concat(d, l, r) => write!(f, "Concat R{}, R{}, R{}", d, l, r),
289 Instruction::CallMethod(obj, method, args, cnt, dest) => {
290 if *cnt == 0 {
291 write!(f, "CallMethod R{}, K{}, <no args>, R{}", obj, method, dest)
292 } else {
293 let arg_start = *args as usize;
294 let arg_end = arg_start + (*cnt as usize) - 1;
295 write!(
296 f,
297 "CallMethod R{}, K{}, R{}..R{}, R{}",
298 obj, method, args, arg_end, dest
299 )
300 }
301 }
302
303 Instruction::TypeIs(d, val, type_name) => {
304 write!(f, "TypeIs R{}, R{}, K{}", d, val, type_name)
305 }
306
307 Instruction::LoadUpvalue(d, idx) => write!(f, "LoadUpvalue R{}, U{}", d, idx),
308 Instruction::StoreUpvalue(idx, s) => write!(f, "StoreUpvalue U{}, R{}", idx, s),
309 Instruction::Closure(d, func, upvals, cnt) => {
310 if *cnt == 0 {
311 write!(f, "Closure R{}, F{}, <no upvalues>", d, func)
312 } else {
313 let start = *upvals as usize;
314 let end = start + (*cnt as usize) - 1;
315 write!(f, "Closure R{}, F{}, R{}..R{}", d, func, upvals, end)
316 }
317 }
318 }
319 }
320}