1use std::collections::HashMap;
2
3use byteorder;
4use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
5
6use strum::{EnumCount, EnumIter};
7
8#[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 return unsafe { ::std::mem::transmute(op) };
334}
335
336impl Instructions {
337 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 return Instructions {
370 data: ins
371 .iter()
372 .fold(vec![], |sum, &i| [sum.as_slice(), i.data.as_slice()].concat()),
373 };
374 }
375}