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