Skip to main content

compiler/
op_code.rs

1use std::collections::HashMap;
2
3use byteorder;
4use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
5
6use strum::{EnumCount, EnumIter, FromRepr};
7
8// why not type, see https://stackoverflow.com/a/35569079/1713757
9#[derive(Hash, Eq, Debug, Clone, PartialEq, PartialOrd)]
10pub struct Instructions {
11    pub data: Vec<u8>,
12}
13
14pub struct OpcodeDefinition {
15    pub(crate) name: &'static str,
16    operand_width: Vec<i32>,
17}
18
19impl OpcodeDefinition {
20    pub fn name(&self) -> &'static str {
21        self.name
22    }
23
24    pub fn operand_widths(&self) -> &[i32] {
25        &self.operand_width
26    }
27}
28
29#[repr(u8)]
30#[derive(Debug, Hash, Eq, Clone, Copy, PartialEq, EnumCount, EnumIter, FromRepr)]
31pub enum Opcode {
32    OpConst,
33    OpAdd,
34    OpPop,
35    OpSub,
36    OpMul,
37    OpDiv,
38    OpTrue,
39    OpFalse,
40    OpEqual,
41    OpNotEqual,
42    OpGreaterThan,
43    OpMinus,
44    OpBang,
45    OpJumpNotTruthy,
46    OpJump,
47    OpNull,
48    OpGetGlobal,
49    OpSetGlobal,
50    OpArray,
51    OpHash,
52    OpIndex,
53    OpCall,
54    OpReturnValue,
55    OpReturn,
56    OpGetLocal,
57    OpSetLocal,
58    OpGetBuiltin,
59    OpClosure,
60    OpGetFree,
61    OpCurrentClosure,
62    OpClass,
63    OpMethod,
64    OpGetProperty,
65    OpSetProperty,
66    OpNew,
67}
68
69lazy_static! {
70    pub static ref DEFINITIONS: HashMap<Opcode, OpcodeDefinition> = {
71        let mut m = HashMap::new();
72        m.insert(
73            Opcode::OpConst,
74            OpcodeDefinition {
75                name: "OpConst",
76                operand_width: vec![2],
77            },
78        );
79        m.insert(
80            Opcode::OpAdd,
81            OpcodeDefinition {
82                name: "OpAdd",
83                operand_width: vec![],
84            },
85        );
86        m.insert(
87            Opcode::OpPop,
88            OpcodeDefinition {
89                name: "OpPop",
90                operand_width: vec![],
91            },
92        );
93        m.insert(
94            Opcode::OpSub,
95            OpcodeDefinition {
96                name: "OpSub",
97                operand_width: vec![],
98            },
99        );
100        m.insert(
101            Opcode::OpMul,
102            OpcodeDefinition {
103                name: "OpMul",
104                operand_width: vec![],
105            },
106        );
107        m.insert(
108            Opcode::OpDiv,
109            OpcodeDefinition {
110                name: "OpDiv",
111                operand_width: vec![],
112            },
113        );
114        m.insert(
115            Opcode::OpTrue,
116            OpcodeDefinition {
117                name: "OpTrue",
118                operand_width: vec![],
119            },
120        );
121        m.insert(
122            Opcode::OpFalse,
123            OpcodeDefinition {
124                name: "OpFalse",
125                operand_width: vec![],
126            },
127        );
128        m.insert(
129            Opcode::OpEqual,
130            OpcodeDefinition {
131                name: "OpEqual",
132                operand_width: vec![],
133            },
134        );
135        m.insert(
136            Opcode::OpNotEqual,
137            OpcodeDefinition {
138                name: "OpNotEqual",
139                operand_width: vec![],
140            },
141        );
142        m.insert(
143            Opcode::OpGreaterThan,
144            OpcodeDefinition {
145                name: "OpGreatThan",
146                operand_width: vec![],
147            },
148        );
149        m.insert(
150            Opcode::OpMinus,
151            OpcodeDefinition {
152                name: "OpMinus",
153                operand_width: vec![],
154            },
155        );
156        m.insert(
157            Opcode::OpBang,
158            OpcodeDefinition {
159                name: "OpBang",
160                operand_width: vec![],
161            },
162        );
163        m.insert(
164            Opcode::OpJumpNotTruthy,
165            OpcodeDefinition {
166                name: "OpJumpNotTruthy",
167                operand_width: vec![2],
168            },
169        );
170        m.insert(
171            Opcode::OpJump,
172            OpcodeDefinition {
173                name: "OpJump",
174                operand_width: vec![2],
175            },
176        );
177        m.insert(
178            Opcode::OpNull,
179            OpcodeDefinition {
180                name: "OpNull",
181                operand_width: vec![],
182            },
183        );
184        m.insert(
185            Opcode::OpGetGlobal,
186            OpcodeDefinition {
187                name: "OpGetGlobal",
188                operand_width: vec![2],
189            },
190        );
191        m.insert(
192            Opcode::OpSetGlobal,
193            OpcodeDefinition {
194                name: "OpSetGlobal",
195                operand_width: vec![2],
196            },
197        );
198        m.insert(
199            Opcode::OpArray,
200            OpcodeDefinition {
201                name: "OpArray",
202                operand_width: vec![2],
203            },
204        );
205        m.insert(
206            Opcode::OpHash,
207            OpcodeDefinition {
208                name: "OpHash",
209                operand_width: vec![2],
210            },
211        );
212        m.insert(
213            Opcode::OpIndex,
214            OpcodeDefinition {
215                name: "OpIndex",
216                operand_width: vec![],
217            },
218        );
219        m.insert(
220            Opcode::OpCall,
221            OpcodeDefinition {
222                name: "OpCall",
223                operand_width: vec![1],
224            },
225        );
226        m.insert(
227            Opcode::OpReturn,
228            OpcodeDefinition {
229                name: "OpReturn",
230                operand_width: vec![],
231            },
232        );
233        m.insert(
234            Opcode::OpReturnValue,
235            OpcodeDefinition {
236                name: "OpReturnValue",
237                operand_width: vec![],
238            },
239        );
240        m.insert(
241            Opcode::OpGetLocal,
242            OpcodeDefinition {
243                name: "OpGetLocal",
244                operand_width: vec![1],
245            },
246        );
247        m.insert(
248            Opcode::OpSetLocal,
249            OpcodeDefinition {
250                name: "OpSetLocal",
251                operand_width: vec![1],
252            },
253        );
254        m.insert(
255            Opcode::OpGetBuiltin,
256            OpcodeDefinition {
257                name: "OpGetBuiltin",
258                operand_width: vec![1],
259            },
260        );
261        m.insert(
262            Opcode::OpClosure,
263            OpcodeDefinition {
264                name: "OpClosure",
265                operand_width: vec![2, 1],
266            },
267        );
268        m.insert(
269            Opcode::OpGetFree,
270            OpcodeDefinition {
271                name: "OpGetFree",
272                operand_width: vec![1],
273            },
274        );
275        m.insert(
276            Opcode::OpCurrentClosure,
277            OpcodeDefinition {
278                name: "OpCurrentClosure",
279                operand_width: vec![],
280            },
281        );
282        m.insert(
283            Opcode::OpClass,
284            OpcodeDefinition {
285                name: "OpClass",
286                operand_width: vec![2],
287            },
288        );
289        m.insert(
290            Opcode::OpMethod,
291            OpcodeDefinition {
292                name: "OpMethod",
293                operand_width: vec![2, 1],
294            },
295        );
296        m.insert(
297            Opcode::OpGetProperty,
298            OpcodeDefinition {
299                name: "OpGetProperty",
300                operand_width: vec![2],
301            },
302        );
303        m.insert(
304            Opcode::OpSetProperty,
305            OpcodeDefinition {
306                name: "OpSetProperty",
307                operand_width: vec![2],
308            },
309        );
310        m.insert(
311            Opcode::OpNew,
312            OpcodeDefinition {
313                name: "OpNew",
314                operand_width: vec![1],
315            },
316        );
317        return m;
318    };
319}
320
321pub fn make_instructions(op: Opcode, operands: &Vec<usize>) -> Instructions {
322    let mut instructions = Vec::new();
323    instructions.push(op as u8);
324    let widths = &DEFINITIONS.get(&op).unwrap().operand_width;
325
326    for (o, w) in operands.into_iter().zip(widths) {
327        match w {
328            2 => {
329                instructions.write_u16::<BigEndian>(*o as u16).unwrap();
330            }
331            1 => {
332                instructions.write_u8(*o as u8).unwrap();
333            }
334            _ => {
335                panic!("unsupported operand width {}", w)
336            }
337        }
338    }
339
340    return Instructions {
341        data: instructions,
342    };
343}
344
345pub fn read_operands(def: &OpcodeDefinition, ins: &[u8]) -> (Vec<usize>, usize) {
346    let mut operands = Vec::with_capacity(def.operand_width.len());
347    let mut offset = 0;
348
349    for w in &def.operand_width {
350        match w {
351            2 => {
352                operands.push(BigEndian::read_u16(&ins[offset..offset + 2]) as usize);
353                offset = offset + 2;
354            }
355            1 => {
356                operands.push(ins[offset] as usize);
357                offset = offset + 1;
358            }
359            0 => {}
360            _ => {
361                panic!("unsupported operand width {} for read", w)
362            }
363        }
364    }
365
366    return (operands, offset);
367}
368
369pub fn concat_instructions(expected: &Vec<Instructions>) -> Instructions {
370    let mut out = Instructions {
371        data: vec![],
372    };
373
374    for instruction in expected {
375        out = out.merge_instructions(instruction)
376    }
377
378    return out;
379}
380
381impl Instructions {
382    // prettify bytecodes
383    pub fn string(&self) -> String {
384        let mut ret = String::new();
385        let mut i = 0;
386        while i < self.data.len() {
387            let op: u8 = self.data[i];
388            let Some(opcode) = Opcode::from_repr(op) else {
389                ret.push_str(&format!("{:04} <unknown opcode 0x{:02x}>\n", i, op));
390                i += 1;
391                continue;
392            };
393
394            let definition = DEFINITIONS.get(&opcode).unwrap();
395            let width: usize = definition.operand_width.iter().map(|w| *w as usize).sum();
396            if i + 1 + width > self.data.len() {
397                ret.push_str(&format!("{:04} {} <truncated operands>\n", i, definition.name));
398                break;
399            }
400            let (operands, read_size) = read_operands(definition, &self.data[i + 1..]);
401            ret.push_str(&format!("{:04} {}\n", i, Self::fmt_instructions(definition, &operands)));
402            i = i + 1 + read_size;
403        }
404
405        return ret;
406    }
407
408    fn fmt_instructions(def: &OpcodeDefinition, operands: &Vec<usize>) -> String {
409        match def.operand_width.len() {
410            2 => format!("{} {} {}", def.name, operands[0], operands[1]),
411            1 => format!("{} {}", def.name, operands[0]),
412            0 => format!("{}", def.name),
413            _ => {
414                panic!("unsupported operand width {}", def.operand_width.len());
415            }
416        }
417    }
418
419    pub fn merge_instructions(&self, other: &Instructions) -> Instructions {
420        let ins = vec![self, other];
421        // Maybe extend_from_slice, but I have not make it work
422        // https://stackoverflow.com/a/69578632/1713757
423        return Instructions {
424            data: ins
425                .iter()
426                .fold(vec![], |sum, &i| [sum.as_slice(), i.data.as_slice()].concat()),
427        };
428    }
429}