1use crate::bytecode_encoder::error::BindRulesEncodeError;
6use crate::compiler::instruction::{Condition, Instruction, InstructionInfo};
7use crate::compiler::{BindRules, BindRulesDecodeError, Symbol, SymbolicInstructionInfo};
8
9use bitfield::bitfield;
10use byteorder::ByteOrder;
11use num_derive::FromPrimitive;
12use std::fmt;
13
14#[derive(FromPrimitive, PartialEq, Clone, Copy)]
19pub enum RawOp {
20 Abort = 0,
21 Match,
22 Goto,
23 Label = 5,
24}
25
26#[derive(FromPrimitive, PartialEq, Clone, Copy, Debug)]
28pub enum RawCondition {
29 Always = 0,
30 Equal,
31 NotEqual,
32}
33
34bitfield! {
35 pub struct RawInstruction([u32]);
47 u32;
48 pub condition, set_condition: 31, 28;
49 pub operation, set_operation: 27, 24;
50 pub parameter_a, set_parameter_a: 23, 16;
51 pub parameter_b, set_parameter_b: 15, 0;
52 pub value, set_value: 63, 32;
53 pub line, set_line: 95, 88;
54 pub ast_location, set_ast_location: 87, 80;
55 pub extra, set_extra: 79, 64;
56}
57
58impl fmt::Display for RawInstruction<[u32; 3]> {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 write!(
61 f,
62 "c: {}, o: {}, a: {}, b: {:#06x}, v: {:#010x}",
63 self.condition(),
64 self.operation(),
65 self.parameter_a(),
66 self.parameter_b(),
67 self.value()
68 )
69 }
70}
71
72pub fn to_raw_instruction(
73 instruction: Instruction,
74) -> Result<RawInstruction<[u32; 3]>, BindRulesEncodeError> {
75 let (c, o, a, b, v) = match instruction {
76 Instruction::Abort(condition) => {
77 let (c, b, v) = encode_condition(condition)?;
78 Ok((c, RawOp::Abort as u32, 0, b, v))
79 }
80 Instruction::Match(condition) => {
81 let (c, b, v) = encode_condition(condition)?;
82 Ok((c, RawOp::Match as u32, 0, b, v))
83 }
84 Instruction::Goto(condition, a) => {
85 let (c, b, v) = encode_condition(condition)?;
86 Ok((c, RawOp::Goto as u32, a, b, v))
87 }
88 Instruction::Label(a) => Ok((RawCondition::Always as u32, RawOp::Label as u32, a, 0, 0)),
89 }?;
90
91 let mut raw_instruction = RawInstruction([0, 0, 0]);
92 raw_instruction.set_condition(c);
93 raw_instruction.set_operation(o);
94 raw_instruction.set_parameter_a(a);
95 raw_instruction.set_parameter_b(b);
96 raw_instruction.set_value(v);
97 Ok(raw_instruction)
98}
99
100fn encode_condition(condition: Condition) -> Result<(u32, u32, u32), BindRulesEncodeError> {
101 match condition {
102 Condition::Always => Ok((RawCondition::Always as u32, 0, 0)),
103 Condition::Equal(b, v) => {
104 let b_sym = encode_symbol(b)?;
105 let v_sym = encode_symbol(v)?;
106 Ok((RawCondition::Equal as u32, b_sym, v_sym))
107 }
108 Condition::NotEqual(b, v) => {
109 let b_sym = encode_symbol(b)?;
110 let v_sym = encode_symbol(v)?;
111 Ok((RawCondition::NotEqual as u32, b_sym, v_sym))
112 }
113 }
114}
115
116pub fn encode_symbol(symbol: Symbol) -> Result<u32, BindRulesEncodeError> {
117 match symbol {
119 Symbol::DeprecatedKey(value) => Ok(value),
120 Symbol::NumberValue(value64) => match u32::try_from(value64) {
121 Ok(value32) => Ok(value32),
122 _ => Err(BindRulesEncodeError::IntegerOutOfRange),
123 },
124 _ => Err(BindRulesEncodeError::UnsupportedSymbol),
125 }
126}
127
128pub fn encode_instruction(
129 info: InstructionInfo,
130) -> Result<RawInstruction<[u32; 3]>, BindRulesEncodeError> {
131 let mut raw_instruction = to_raw_instruction(info.instruction)?;
132 raw_instruction.set_line(info.debug.line);
133 raw_instruction.set_ast_location(info.debug.ast_location as u32);
134 raw_instruction.set_extra(info.debug.extra);
135 Ok(raw_instruction)
136}
137
138pub fn decode_from_bytecode_v1(
139 bytes: &Vec<u8>,
140) -> Result<Vec<RawInstruction<[u32; 3]>>, BindRulesDecodeError> {
141 if bytes.len() % 12 != 0 {
142 return Err(BindRulesDecodeError::InvalidBinaryLength);
143 }
144 let mut instructions = Vec::<RawInstruction<[u32; 3]>>::new();
145 for i in (0..bytes.len()).step_by(12) {
146 let first = byteorder::LittleEndian::read_u32(&bytes[i..(i + 4)]);
147 let second = byteorder::LittleEndian::read_u32(&bytes[(i + 4)..(i + 8)]);
148 let third = byteorder::LittleEndian::read_u32(&bytes[(i + 8)..(i + 12)]);
149 instructions.push(RawInstruction([first, second, third]));
150 }
151 Ok(instructions)
152}
153
154pub fn encode_to_bytecode_v1(bind_rules: BindRules) -> Result<Vec<u8>, BindRulesEncodeError> {
155 let result = bind_rules
156 .instructions
157 .into_iter()
158 .map(|inst| encode_instruction(inst.to_instruction()))
159 .collect::<Result<Vec<_>, BindRulesEncodeError>>()?;
160 Ok(result
161 .into_iter()
162 .flat_map(|RawInstruction([a, b, c])| {
163 [a.to_le_bytes(), b.to_le_bytes(), c.to_le_bytes()].concat()
164 })
165 .collect::<Vec<_>>())
166}
167
168pub fn encode_to_string_v1<'a>(
169 instructions: Vec<SymbolicInstructionInfo<'a>>,
170) -> Result<String, BindRulesEncodeError> {
171 let result = instructions
172 .into_iter()
173 .map(|inst| encode_instruction(inst.to_instruction()))
174 .collect::<Result<Vec<_>, BindRulesEncodeError>>()?;
175 #[allow(clippy::format_collect, reason = "mass allow for https://fxbug.dev/381896734")]
176 Ok(result
177 .into_iter()
178 .map(|RawInstruction([word0, word1, word2])| {
179 format!("{{{:#x},{:#x},{:#x}}},", word0, word1, word2)
180 })
181 .collect::<String>())
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use crate::compiler::SymbolicInstruction;
188 use std::collections::HashMap;
189
190 #[test]
191 fn test_raw_instruction() {
192 let mut raw = RawInstruction([0, 0]);
193 assert_eq!(raw.0[0], 0);
194 assert_eq!(raw.0[1], 0);
195 assert_eq!(raw.condition(), 0);
196 assert_eq!(raw.operation(), 0);
197 assert_eq!(raw.parameter_a(), 0);
198 assert_eq!(raw.parameter_b(), 0);
199 assert_eq!(raw.value(), 0);
200
201 raw.set_condition(1);
202 assert_eq!(raw.0[0], 1 << 28);
203 assert_eq!(raw.0[1], 0);
204 assert_eq!(raw.condition(), 1);
205 assert_eq!(raw.operation(), 0);
206 assert_eq!(raw.parameter_a(), 0);
207 assert_eq!(raw.parameter_b(), 0);
208 assert_eq!(raw.value(), 0);
209
210 raw.set_operation(2);
211 assert_eq!(raw.0[0], (1 << 28) | (2 << 24));
212 assert_eq!(raw.0[1], 0);
213 assert_eq!(raw.condition(), 1);
214 assert_eq!(raw.operation(), 2);
215 assert_eq!(raw.parameter_a(), 0);
216 assert_eq!(raw.parameter_b(), 0);
217 assert_eq!(raw.value(), 0);
218
219 raw.set_parameter_a(3);
220 assert_eq!(raw.0[0], (1 << 28) | (2 << 24) | (3 << 16));
221 assert_eq!(raw.0[1], 0);
222 assert_eq!(raw.condition(), 1);
223 assert_eq!(raw.operation(), 2);
224 assert_eq!(raw.parameter_a(), 3);
225 assert_eq!(raw.parameter_b(), 0);
226 assert_eq!(raw.value(), 0);
227
228 raw.set_parameter_b(4);
229 assert_eq!(raw.0[0], (1 << 28) | (2 << 24) | (3 << 16) | 4);
230 assert_eq!(raw.0[1], 0);
231 assert_eq!(raw.condition(), 1);
232 assert_eq!(raw.operation(), 2);
233 assert_eq!(raw.parameter_a(), 3);
234 assert_eq!(raw.parameter_b(), 4);
235 assert_eq!(raw.value(), 0);
236
237 raw.set_value(5);
238 assert_eq!(raw.0[0], (1 << 28) | (2 << 24) | (3 << 16) | 4);
239 assert_eq!(raw.0[1], 5);
240 assert_eq!(raw.condition(), 1);
241 assert_eq!(raw.operation(), 2);
242 assert_eq!(raw.parameter_a(), 3);
243 assert_eq!(raw.parameter_b(), 4);
244 assert_eq!(raw.value(), 5)
245 }
246
247 #[test]
248 fn test_abort_value() {
249 let instruction = Instruction::Abort(Condition::Always);
250 let raw_instruction = to_raw_instruction(instruction).unwrap();
251 assert_eq!(raw_instruction.0[0], 0 << 4);
252 assert_eq!(raw_instruction.0[1], 0);
253 assert_eq!(raw_instruction.operation(), 0)
254 }
255
256 #[test]
257 fn test_match_value() {
258 let instruction = Instruction::Match(Condition::Always);
259 let raw_instruction = to_raw_instruction(instruction).unwrap();
260 assert_eq!(raw_instruction.0[0], 1 << 24);
261 assert_eq!(raw_instruction.0[1], 0);
262 assert_eq!(raw_instruction.operation(), 1)
263 }
264
265 #[test]
266 fn test_goto_value() {
267 let instruction = Instruction::Goto(Condition::Always, 0);
268 let raw_instruction = to_raw_instruction(instruction).unwrap();
269 assert_eq!(raw_instruction.0[0], 2 << 24);
270 assert_eq!(raw_instruction.0[1], 0);
271 assert_eq!(raw_instruction.operation(), 2)
272 }
273
274 #[test]
275 fn test_label_value() {
276 let instruction = Instruction::Label(0);
277 let raw_instruction = to_raw_instruction(instruction).unwrap();
278 assert_eq!(raw_instruction.0[0], 5 << 24);
279 assert_eq!(raw_instruction.0[1], 0);
280 assert_eq!(raw_instruction.operation(), 5)
281 }
282
283 #[test]
284 fn test_complicated_value() {
285 let instruction = Instruction::Goto(
286 Condition::Equal(Symbol::NumberValue(23), Symbol::NumberValue(1234)),
287 42,
288 );
289 let raw_instruction = to_raw_instruction(instruction).unwrap();
290 assert_eq!(raw_instruction.0[0], (1 << 28) | (2 << 24) | (42 << 16) | 23);
291 assert_eq!(raw_instruction.0[1], 1234);
292 assert_eq!(raw_instruction.condition(), 1);
293 assert_eq!(raw_instruction.operation(), 2);
294 assert_eq!(raw_instruction.parameter_a(), 42);
295 assert_eq!(raw_instruction.parameter_b(), 23);
296 assert_eq!(raw_instruction.value(), 1234);
297 }
298
299 #[test]
300 fn test_unsupported_symbols() {
301 let bind_rules = BindRules {
302 instructions: vec![SymbolicInstructionInfo {
303 location: None,
304 instruction: SymbolicInstruction::AbortIfNotEqual {
305 lhs: Symbol::StringValue("kingbird".to_string()),
306 rhs: Symbol::StringValue("flycatcher".to_string()),
307 },
308 }],
309 symbol_table: HashMap::new(),
310 use_new_bytecode: false,
311 enable_debug: false,
312 };
313
314 assert_eq!(Err(BindRulesEncodeError::UnsupportedSymbol), encode_to_bytecode_v1(bind_rules));
315
316 let bind_rules = BindRules {
317 instructions: vec![SymbolicInstructionInfo {
318 location: None,
319 instruction: SymbolicInstruction::AbortIfNotEqual {
320 lhs: Symbol::NumberValue(u64::MAX),
321 rhs: Symbol::NumberValue(0),
322 },
323 }],
324 symbol_table: HashMap::new(),
325 use_new_bytecode: false,
326 enable_debug: false,
327 };
328
329 assert_eq!(Err(BindRulesEncodeError::IntegerOutOfRange), encode_to_bytecode_v1(bind_rules));
330 }
331
332 #[test]
333 fn test_decode_wrong_size() {
334 let bytes = vec![1u8; 3];
335 assert_eq!(
336 decode_from_bytecode_v1(&bytes).err(),
337 Some(BindRulesDecodeError::InvalidBinaryLength)
338 );
339
340 let bytes = vec![1u8; 13];
341 assert_eq!(
342 decode_from_bytecode_v1(&bytes).err(),
343 Some(BindRulesDecodeError::InvalidBinaryLength)
344 );
345 }
346
347 #[test]
348 fn test_encode_and_decode() {
349 let bytes = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
350 let instructions = decode_from_bytecode_v1(&bytes).unwrap();
351 let new_bytes = instructions
352 .into_iter()
353 .flat_map(|RawInstruction([a, b, c])| {
354 [a.to_le_bytes(), b.to_le_bytes(), c.to_le_bytes()].concat()
355 })
356 .collect::<Vec<_>>();
357 assert_eq!(bytes, new_bytes);
358 }
359}