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(Opcode::OpConst, OpcodeDefinition { name: "OpConst", operand_width: vec![2] });
58 m.insert(Opcode::OpAdd, OpcodeDefinition { name: "OpAdd", operand_width: vec![] });
59 m.insert(Opcode::OpPop, OpcodeDefinition { name: "OpPop", operand_width: vec![] });
60 m.insert(Opcode::OpSub, OpcodeDefinition { name: "OpSub", operand_width: vec![] });
61 m.insert(Opcode::OpMul, OpcodeDefinition { name: "OpMul", operand_width: vec![] });
62 m.insert(Opcode::OpDiv, OpcodeDefinition { name: "OpDiv", operand_width: vec![] });
63 m.insert(Opcode::OpTrue, OpcodeDefinition { name: "OpTrue", operand_width: vec![] });
64 m.insert(Opcode::OpFalse, OpcodeDefinition { name: "OpFalse", operand_width: vec![] });
65 m.insert(Opcode::OpEqual, OpcodeDefinition { name: "OpEqual", operand_width: vec![] });
66 m.insert(
67 Opcode::OpNotEqual,
68 OpcodeDefinition { name: "OpNotEqual", operand_width: vec![] },
69 );
70 m.insert(
71 Opcode::OpGreaterThan,
72 OpcodeDefinition { name: "OpGreatThan", operand_width: vec![] },
73 );
74 m.insert(Opcode::OpMinus, OpcodeDefinition { name: "OpMinus", operand_width: vec![] });
75 m.insert(Opcode::OpBang, OpcodeDefinition { name: "OpBang", operand_width: vec![] });
76 m.insert(
77 Opcode::OpJumpNotTruthy,
78 OpcodeDefinition { name: "OpJumpNotTruthy", operand_width: vec![2] },
79 );
80 m.insert(Opcode::OpJump, OpcodeDefinition { name: "OpJump", operand_width: vec![2] });
81 m.insert(Opcode::OpNull, OpcodeDefinition { name: "OpNull", operand_width: vec![] });
82 m.insert(
83 Opcode::OpGetGlobal,
84 OpcodeDefinition { name: "OpGetGlobal", operand_width: vec![2] },
85 );
86 m.insert(
87 Opcode::OpSetGlobal,
88 OpcodeDefinition { name: "OpSetGlobal", operand_width: vec![2] },
89 );
90 m.insert(Opcode::OpArray, OpcodeDefinition { name: "OpArray", operand_width: vec![2] });
91 m.insert(Opcode::OpHash, OpcodeDefinition { name: "OpHash", operand_width: vec![2] });
92 m.insert(Opcode::OpIndex, OpcodeDefinition { name: "OpIndex", operand_width: vec![] });
93 m.insert(Opcode::OpCall, OpcodeDefinition { name: "OpCall", operand_width: vec![1] });
94 m.insert(Opcode::OpReturn, OpcodeDefinition { name: "OpReturn", operand_width: vec![] });
95 m.insert(
96 Opcode::OpReturnValue,
97 OpcodeDefinition { name: "OpReturnValue", operand_width: vec![] },
98 );
99 m.insert(
100 Opcode::OpGetLocal,
101 OpcodeDefinition { name: "OpGetLocal", operand_width: vec![1] },
102 );
103 m.insert(
104 Opcode::OpSetLocal,
105 OpcodeDefinition { name: "OpSetLocal", operand_width: vec![1] },
106 );
107 m.insert(
108 Opcode::OpGetBuiltin,
109 OpcodeDefinition { name: "OpGetBuiltin", operand_width: vec![1] },
110 );
111 m.insert(
112 Opcode::OpClosure,
113 OpcodeDefinition { name: "OpClosure", operand_width: vec![2, 1] },
114 );
115 m.insert(
116 Opcode::OpGetFree,
117 OpcodeDefinition { name: "OpGetFree", operand_width: vec![1] },
118 );
119 m.insert(
120 Opcode::OpCurrentClosure,
121 OpcodeDefinition { name: "OpCurrentClosure", operand_width: vec![] },
122 );
123 return m;
124 };
125}
126
127pub fn make_instructions(op: Opcode, operands: &Vec<usize>) -> Instructions {
128 let mut instructions = Vec::new();
129 instructions.push(op as u8);
130 let widths = &DEFINITIONS.get(&op).unwrap().operand_width;
131
132 for (o, w) in operands.into_iter().zip(widths) {
133 match w {
134 2 => {
135 instructions.write_u16::<BigEndian>(*o as u16).unwrap();
136 }
137 1 => {
138 instructions.write_u8(*o as u8).unwrap();
139 }
140 _ => {
141 panic!("unsupported operand width {}", w)
142 }
143 }
144 }
145
146 return Instructions { data: instructions };
147}
148
149pub fn read_operands(def: &OpcodeDefinition, ins: &[u8]) -> (Vec<usize>, usize) {
150 let mut operands = Vec::with_capacity(def.operand_width.len());
151 let mut offset = 0;
152
153 for w in &def.operand_width {
154 match w {
155 2 => {
156 operands.push(BigEndian::read_u16(&ins[offset..offset + 2]) as usize);
157 offset = offset + 2;
158 }
159 1 => {
160 operands.push(ins[offset] as usize);
161 offset = offset + 1;
162 }
163 0 => {}
164 _ => {
165 panic!("unsupported operand width {} for read", w)
166 }
167 }
168 }
169
170 return (operands, offset);
171}
172
173pub fn concat_instructions(expected: &Vec<Instructions>) -> Instructions {
174 let mut out = Instructions { data: vec![] };
175
176 for instruction in expected {
177 out = out.merge_instructions(instruction)
178 }
179
180 return out;
181}
182
183pub fn cast_u8_to_opcode(op: u8) -> Opcode {
184 return unsafe { ::std::mem::transmute(op) };
186}
187
188impl Instructions {
189 pub fn string(&self) -> String {
191 let mut ret = String::new();
192 let mut i = 0;
193 while i < self.data.len() {
194 let op: u8 = *self.data.get(i).unwrap();
195 let opcode = cast_u8_to_opcode(op);
196
197 let definition = DEFINITIONS.get(&opcode).unwrap();
198 let (operands, read_size) = read_operands(definition, &self.data[i + 1..]);
199 ret.push_str(&format!("{:04} {}\n", i, Self::fmt_instructions(definition, &operands)));
200 i = i + 1 + read_size;
201 }
202
203 return ret;
204 }
205
206 fn fmt_instructions(def: &OpcodeDefinition, operands: &Vec<usize>) -> String {
207 match def.operand_width.len() {
208 2 => format!("{} {} {}", def.name, operands[0], operands[1]),
209 1 => format!("{} {}", def.name, operands[0]),
210 0 => format!("{}", def.name),
211 _ => {
212 panic!("unsupported operand width {}", def.operand_width.len());
213 }
214 }
215 }
216
217 pub fn merge_instructions(&self, other: &Instructions) -> Instructions {
218 let ins = vec![self, other];
219 return Instructions {
222 data: ins
223 .iter()
224 .fold(vec![], |sum, &i| [sum.as_slice(), i.data.as_slice()].concat()),
225 };
226 }
227}