1use byteorder::{ByteOrder, LittleEndian};
4use failure::Fail;
5use strum_macros::Display;
6
7use crate::context::Context;
8
9use std::fmt;
10
11#[derive(Clone, PartialEq, Eq, Debug)]
19pub enum Expr {
20 Ident(String),
21 Const(i64),
22 Func(Box<Expr>, Box<Expr>),
23 Binary(Box<BinaryExpr>),
24 Unary(Box<UnaryExpr>),
25}
26
27impl fmt::Display for Expr {
28 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29 match self {
30 Expr::Ident(ident) => write!(f, "{}", ident),
31 Expr::Const(c) => write!(f, "{}", c),
32 Expr::Func(f_name, f_arg) => write!(f, "{}({})", f_name, f_arg),
33 Expr::Binary(binary) => write!(f, "{}", binary),
34 Expr::Unary(unary) => write!(f, "{}", unary),
35 }
36 }
37}
38
39impl Expr {
40 pub fn binary(left: Expr, operator: BinaryOperator, right: Expr) -> Expr {
41 Expr::Binary(Box::new(BinaryExpr {
42 left,
43 operator,
44 right,
45 }))
46 }
47
48 pub fn unary(expr: Expr, operator: UnaryOperator) -> Expr {
49 Expr::Unary(Box::new(UnaryExpr { expr, operator }))
50 }
51
52 pub fn get_words(&self, constants: &dyn Context) -> Result<[u8; 2], ExprRunError> {
53 let value = self.run(constants)?;
54 if value > 0xFFFF || value < -32768 {
55 Err(ExprRunError::ResultDoesntFit(format!(
56 "0x{} > 0xFFFF This is invalid because the value needs to fit in word",
57 value
58 )))
59 } else {
60 let mut result = [0, 0];
61 LittleEndian::write_u16(&mut result, value as u16);
62 Ok(result)
63 }
64 }
65
66 pub fn get_double_words(&self, constants: &dyn Context) -> Result<[u8; 4], ExprRunError> {
67 let value = self.run(constants)?;
68 if value > std::u32::MAX as i64 || value < std::i32::MIN as i64 {
69 Err(ExprRunError::ResultDoesntFit(format!(
70 "0x{} > 0xFFFF_FFFF This is invalid because the value needs to fit in word",
71 value
72 )))
73 } else {
74 let mut result = [0, 0, 0, 0];
75 LittleEndian::write_u32(&mut result, value as u32);
76 Ok(result)
77 }
78 }
79
80 pub fn get_quad_words(&self, constants: &dyn Context) -> Result<[u8; 8], ExprRunError> {
81 let value = self.run(constants)?;
82
83 let mut result = [0, 0, 0, 0, 0, 0, 0, 0];
84 LittleEndian::write_u64(&mut result, value as u64);
85 Ok(result)
86 }
87
88 pub fn get_byte(&self, constants: &dyn Context) -> Result<u8, ExprRunError> {
89 let value = self.run(constants)?;
90 if value > 0xFF || value < -128 {
91 Err(ExprRunError::ResultDoesntFit(format!(
92 "0x{:x} > 0xFF This is invalid because the value needs to fit in one byte",
93 value
94 )))
95 } else {
96 Ok(value as u8)
97 }
98 }
99
100 pub fn get_bit_index(&self, constants: &dyn Context) -> Result<u8, ExprRunError> {
101 let value = self.run(constants)?;
102 if value > 7 {
103 Err(ExprRunError::ResultDoesntFit(format!(
104 "{} > 7 This is invalid because the value needs to index bits in a byte.",
105 value
106 )))
107 } else {
108 Ok(value as u8)
109 }
110 }
111
112 pub fn run(&self, constants: &dyn Context) -> Result<i64, ExprRunError> {
113 match self {
114 Expr::Ident(ident) => match constants.get_expr(ident) {
115 Some(Expr::Const(address)) => Ok(address),
116 Some(expr) => expr.run(constants),
118 None => Err(ExprRunError::MissingIdentifier(ident.clone())),
119 },
120 Expr::Const(value) => Ok(*value),
121 Expr::Func(ident, argument) => {
122 if let Expr::Ident(name) = &**ident {
123 let value = argument.run(constants)?;
124 let ret_val = match name.to_lowercase().as_str() {
125 "low" => (value as u64 & 0xff) as i64,
126 "high" | "byte2" => ((value as u64 & 0xff00) >> 8) as i64,
127 "byte3" => ((value as u64 & 0xff0000) >> 16) as i64,
128 "byte4" => ((value as u64 & 0xff000000) >> 24) as i64,
129 "lwrd" => (value as u64 & 0xffff) as i64,
130 "hwrd" => ((value as u64 & 0xffff0000) >> 16) as i64,
131 "page" => ((value as u64 & 0x1f0000) >> 16) as i64,
132 "exp2" => 1 << value,
133 "log2" => {
134 let mut i = 0;
135 let mut value = value as u64;
136 while value > 0 {
137 value >>= 1;
138 i += 1
139 }
140 i
141 }
142 _ => return Err(ExprRunError::MissingFunction(name.clone())),
143 };
144
145 Ok(ret_val)
146 } else {
147 Err(ExprRunError::ResultDoesntFit(format!(
148 "function name must be Ident, get: {:?}",
149 ident
150 )))
151 }
152 }
153 Expr::Binary(binary) => {
154 let left = binary.left.run(constants)?;
155 let right = binary.right.run(constants)?;
156 match binary.operator {
157 BinaryOperator::Add => match left.checked_add(right) {
158 Some(value) => Ok(value),
159 None => Err(ExprRunError::ArithmeticError(format!(
160 "Addition overflowed: {:?} + {:?}",
161 binary.left, binary.right
162 ))),
163 },
164 BinaryOperator::Sub => match left.checked_sub(right) {
165 Some(value) => Ok(value),
166 None => Err(ExprRunError::ArithmeticError(format!(
167 "Subtraction underflowed: {:?} - {:?}",
168 binary.left, binary.right
169 ))),
170 },
171 BinaryOperator::Mul => match left.checked_mul(right) {
172 Some(value) => Ok(value),
173 None => Err(ExprRunError::ArithmeticError(format!(
174 "Multiplication overflowed: {:?} * {:?}",
175 binary.left, binary.right
176 ))),
177 },
178 BinaryOperator::Div => {
179 if right == 0 {
180 Err(ExprRunError::ArithmeticError(format!(
181 "Attempted to divide by zero: {:?} / {:?}",
182 binary.left, binary.right
183 )))
184 } else {
185 match left.checked_div(right) {
186 Some(value) => Ok(value),
187 None => Err(ExprRunError::ArithmeticError(format!(
188 "Division overflowed: {:?} / {:?}",
189 binary.left, binary.right
190 ))),
191 }
192 }
193 }
194 BinaryOperator::Rem => {
195 if right == 0 {
196 Err(ExprRunError::ArithmeticError(format!(
197 "Attempted to divide by zero (remainder): {:?} % {:?}",
198 binary.left, binary.right
199 )))
200 } else {
201 match left.checked_rem(right) {
202 Some(value) => Ok(value),
203 None => Err(ExprRunError::ArithmeticError(format!(
204 "Remainder overflowed: {:?} % {:?}",
205 binary.left, binary.right
206 ))),
207 }
208 }
209 }
210 BinaryOperator::BitwiseAnd => Ok(left & right),
211 BinaryOperator::BitwiseOr => Ok(left | right),
212 BinaryOperator::BitwiseXor => Ok(left ^ right),
213 BinaryOperator::ShiftLeft => Ok(left << right),
214 BinaryOperator::ShiftRight => Ok(left >> right),
215 BinaryOperator::LessThan => Ok((left < right) as i64),
216 BinaryOperator::LessOrEqual => Ok((left <= right) as i64),
217 BinaryOperator::GreaterThan => Ok((left > right) as i64),
218 BinaryOperator::GreaterOrEqual => Ok((left >= right) as i64),
219 BinaryOperator::Equal => Ok((left == right) as i64),
220 BinaryOperator::NotEqual => Ok((left < right) as i64),
221 BinaryOperator::LogicalAnd => Ok((left != 0 && right != 0) as i64),
222 BinaryOperator::LogicalOr => Ok((left != 0 || right != 0) as i64),
223 }
224 }
225 Expr::Unary(unary) => match unary.operator {
226 UnaryOperator::Minus => {
227 let value = unary.expr.run(constants)?;
228 match value.checked_neg() {
229 Some(value) => Ok(value),
230 None => Err(ExprRunError::ArithmeticError(format!(
231 "Failed to get negative value of: {}",
232 value
233 ))),
234 }
235 }
236 UnaryOperator::BitwiseNot => {
237 let value = unary.expr.run(constants)?;
238 Ok(value.reverse_bits())
239 }
240 UnaryOperator::LogicalNot => {
241 let value = unary.expr.run(constants)?;
242 Ok((value == 0) as i64)
243 }
244 },
245 }
246 }
247}
248
249#[derive(Debug, Fail)]
250pub enum ExprRunError {
251 #[fail(display = "Function {} can not be found.", _0)]
252 MissingFunction(String),
253 #[fail(display = "Identifier {} can not be found.", _0)]
254 MissingIdentifier(String),
255 #[fail(display = "Arithmetic error: {}", _0)]
256 ArithmeticError(String),
257 #[fail(display = "{}", _0)]
258 ResultDoesntFit(String),
259}
260
261#[derive(Clone, PartialEq, Eq, Debug)]
262pub struct BinaryExpr {
263 pub left: Expr,
264 pub operator: BinaryOperator,
265 pub right: Expr,
266}
267
268impl fmt::Display for BinaryExpr {
269 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
270 write!(f, "{}{}{}", self.left, self.operator, self.right)
271 }
272}
273
274#[derive(Clone, PartialEq, Eq, Debug)]
275pub struct UnaryExpr {
276 pub operator: UnaryOperator,
277 pub expr: Expr,
278}
279
280impl fmt::Display for UnaryExpr {
281 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
282 write!(f, "{}{}", self.operator, self.expr)
283 }
284}
285
286#[derive(Clone, PartialEq, Eq, Debug, Display)]
287pub enum BinaryOperator {
288 #[strum(serialize = "+")]
289 Add,
290 #[strum(serialize = "-")]
291 Sub,
292 #[strum(serialize = "*")]
293 Mul,
294 #[strum(serialize = "/")]
295 Div,
296 #[strum(serialize = "%")]
297 Rem,
298 #[strum(serialize = "&")]
299 BitwiseAnd,
300 #[strum(serialize = "^")]
301 BitwiseXor,
302 #[strum(serialize = "|")]
303 BitwiseOr,
304 #[strum(serialize = "<<")]
305 ShiftLeft,
306 #[strum(serialize = ">>")]
307 ShiftRight,
308 #[strum(serialize = "<")]
309 LessThan,
310 #[strum(serialize = "<=")]
311 LessOrEqual,
312 #[strum(serialize = ">")]
313 GreaterThan,
314 #[strum(serialize = ">=")]
315 GreaterOrEqual,
316 #[strum(serialize = "==")]
317 Equal,
318 #[strum(serialize = "!=")]
319 NotEqual,
320 #[strum(serialize = "&&")]
321 LogicalAnd,
322 #[strum(serialize = "||")]
323 LogicalOr,
324}
325
326#[derive(Clone, PartialEq, Eq, Debug, Display)]
327pub enum UnaryOperator {
328 #[strum(serialize = "-")]
329 Minus,
330 #[strum(serialize = "~")]
331 BitwiseNot,
332 #[strum(serialize = "!")]
333 LogicalNot,
334}
335
336#[cfg(test)]
337mod parser_tests {
338 use super::*;
339 use crate::document::document;
340
341 #[test]
342 fn e_ident_test() {
343 assert_eq!(document::e_ident("_"), Ok(Expr::Ident("_".to_string())));
344
345 assert_eq!(document::e_ident("l"), Ok(Expr::Ident("l".to_string())));
346
347 assert_eq!(
348 document::e_ident("Test_string_of_ident"),
349 Ok(Expr::Ident("Test_string_of_ident".to_string()))
350 );
351
352 assert!(document::e_ident("4").is_err());
353 }
354
355 #[test]
356 fn e_const_test() {
357 assert_eq!(document::e_const("4"), Ok(Expr::Const(4)));
358
359 assert_eq!(document::e_const("0x3519"), Ok(Expr::Const(0x3519)));
360
361 assert_eq!(document::e_const("$4a"), Ok(Expr::Const(0x4a)));
362
363 assert_eq!(document::e_const("03516"), Ok(Expr::Const(0o3516)));
364
365 assert_eq!(document::e_const("0b110100"), Ok(Expr::Const(0b110100)));
366
367 assert!(document::e_const("4a").is_err());
368
369 assert!(document::e_const("0x4z").is_err());
370
371 assert!(document::e_const("$4y").is_err());
372
373 assert!(document::e_const("0489").is_err());
374
375 assert!(document::e_const("0b2103").is_err());
376 }
377
378 #[test]
379 fn expr_test() {
380 assert_eq!(
381 document::expr("Test_string_of_ident"),
382 Ok(Expr::Ident("Test_string_of_ident".to_string()))
383 );
384
385 assert_eq!(document::expr("03516"), Ok(Expr::Const(0o3516)));
386
387 assert_eq!(document::expr("' '"), Ok(Expr::Const(0x20)));
388
389 assert_eq!(document::expr("(t)"), Ok(Expr::Ident("t".to_string())));
390
391 assert_eq!(
392 document::expr("high(t)"),
393 Ok(Expr::Func(
394 Box::new(Expr::Ident("high".to_string())),
395 Box::new(Expr::Ident("t".to_string()))
396 ))
397 );
398
399 assert_eq!(
400 document::expr("1 << 2 | 1 << 1"),
401 Ok(Expr::Binary(Box::new(BinaryExpr {
402 left: Expr::Binary(Box::new(BinaryExpr {
403 left: Expr::Const(1),
404 operator: BinaryOperator::ShiftLeft,
405 right: Expr::Const(2),
406 })),
407 operator: BinaryOperator::BitwiseOr,
408 right: Expr::Binary(Box::new(BinaryExpr {
409 left: Expr::Const(1),
410 operator: BinaryOperator::ShiftLeft,
411 right: Expr::Const(1),
412 })),
413 })))
414 );
415 }
416}