Skip to main content

lust/bytecode/
instruction.rs

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}