use anyhow::{bail, Result}; use parse_int; use rand; use std::cmp::Ordering; use unescape::unescape; use crate::arg; use crate::assembler; use crate::lexer; pub fn unescape_string(string: &str) -> String { match unescape(string) { Some(x) => x, None => "".to_string(), } } #[derive(Debug, Clone)] pub enum Arg { Char(char), String(String), Number(u16), Variable(String), BinaryExpression { left: Box, right: Box, op: BinaryExpressionOperator, }, } impl assembler::ToCode for Arg { fn to_code(&self) -> String { match self { Arg::Char(x) => format!("'{}'", x.escape_default()), Arg::String(x) => format!("\"{}\"", x.escape_default()), Arg::Number(x) => x.to_string(), Arg::Variable(x) => x.clone(), Arg::BinaryExpression { left, right, op } => { format!("({} {} {})", left.to_code(), op.to_code(), right.to_code()) } } } } impl assembler::ByteResolvable for Arg { fn resolve_number(&self, data: &mut assembler::Data) -> Result { match self { Arg::Char(x) => Ok(*x as u16), Arg::String(x) => { let y = unescape_string(x); if y.len() == 1 { Ok(y.as_bytes()[0] as u16) } else { let bytes = y.as_bytes(); Ok(((bytes[0] as u16) << 8) | bytes[1] as u16) } } Arg::Number(x) => Ok(*x), Arg::Variable(x) => { let mut name = x.clone(); let mut arg: Option; loop { arg = data.constants.get(&name).cloned(); match arg { Some(a) => { match a { arg::Arg::Variable(n) => { name = n; } _ => break Ok(a.resolve_number(data)?), }; } _ => bail!("Variable does not exist: {}", name), } } } Arg::BinaryExpression { left, right, op } => { let left_val = left.resolve_number(data)?; let right_val = right.resolve_number(data)?; Ok(match op { BinaryExpressionOperator::Not => !left_val, BinaryExpressionOperator::And => left_val & right_val, BinaryExpressionOperator::Nand => !(left_val & right_val), BinaryExpressionOperator::Or => left_val | right_val, BinaryExpressionOperator::Nor => !(left_val | right_val), BinaryExpressionOperator::Xor => left_val ^ right_val, BinaryExpressionOperator::Xnor => !(left_val ^ right_val), BinaryExpressionOperator::Lsh => left_val << right_val, BinaryExpressionOperator::Rsh => left_val >> right_val, BinaryExpressionOperator::Add => left_val.wrapping_add(right_val), BinaryExpressionOperator::Sub => left_val.wrapping_sub(right_val), BinaryExpressionOperator::Mul => left_val.wrapping_mul(right_val), BinaryExpressionOperator::Div => left_val.wrapping_div(right_val), BinaryExpressionOperator::Pow => left_val.wrapping_pow(right_val as u32), BinaryExpressionOperator::Cmp => match left_val.cmp(&right_val) { Ordering::Equal => 0, Ordering::Less => 1, Ordering::Greater => 2, }, BinaryExpressionOperator::Eq => (left_val == right_val) as u16, BinaryExpressionOperator::Neq => (left_val != right_val) as u16, BinaryExpressionOperator::Lt => (left_val < right_val) as u16, BinaryExpressionOperator::Gt => (left_val > right_val) as u16, BinaryExpressionOperator::Leq => (left_val <= right_val) as u16, BinaryExpressionOperator::Geq => (left_val >= right_val) as u16, BinaryExpressionOperator::Bol => (left_val & 1 == 1) as u16, BinaryExpressionOperator::Inv => (left_val & 1 != 1) as u16, BinaryExpressionOperator::Rnd => rand::random(), }) } } } fn resolve_bytes(&self, data: &mut assembler::Data) -> Result> { match self { Arg::Char(x) => Ok(vec![*x as u8]), Arg::String(x) => Ok(unescape_string(x).bytes().collect()), Arg::Number(x) => Ok(vec![(*x >> 8) as u8, *x as u8]), Arg::Variable(x) => { let mut name = x.clone(); let mut arg: Option; loop { arg = data.constants.get(&name).cloned(); match arg { Some(a) => { match a { arg::Arg::Variable(n) => { name = n; } _ => break Ok(a.resolve_bytes(data)?), }; } _ => bail!("Variable could not be resolved: {}", name), } } } Arg::BinaryExpression { left: _, right: _, op: _, } => { let x = self.resolve_number(data)?; Ok(vec![(x >> 8) as u8, x as u8]) } } } fn resolve_string(&self, data: &mut assembler::Data) -> Result { match self { Arg::Char(x) => Ok(x.to_string()), Arg::String(x) => Ok(x.clone()), Arg::Number(_) => bail!("Number cannot be resolved as string"), Arg::Variable(_) => self.resolve_string(data), Arg::BinaryExpression { left: _, right: _, op: _, } => bail!("Binary expression cannot be resolved as string"), } } } #[derive(Debug, Clone)] pub enum BinaryExpressionOperator { Not, And, Nand, Or, Nor, Xor, Xnor, Lsh, Rsh, Add, Sub, Mul, Div, Pow, Cmp, Eq, Neq, Lt, Gt, Leq, Geq, Bol, Inv, Rnd, } impl assembler::ToCode for BinaryExpressionOperator { fn to_code(&self) -> String { match self { BinaryExpressionOperator::Not => "~".to_string(), BinaryExpressionOperator::And => "&".to_string(), BinaryExpressionOperator::Nand => "~&".to_string(), BinaryExpressionOperator::Or => "|".to_string(), BinaryExpressionOperator::Nor => "~|".to_string(), BinaryExpressionOperator::Xor => "^".to_string(), BinaryExpressionOperator::Xnor => "~^".to_string(), BinaryExpressionOperator::Lsh => "<<".to_string(), BinaryExpressionOperator::Rsh => ">>".to_string(), BinaryExpressionOperator::Add => "+".to_string(), BinaryExpressionOperator::Sub => "-".to_string(), BinaryExpressionOperator::Mul => "*".to_string(), BinaryExpressionOperator::Div => "/".to_string(), BinaryExpressionOperator::Pow => "**".to_string(), BinaryExpressionOperator::Cmp => "<=>".to_string(), BinaryExpressionOperator::Eq => "==".to_string(), BinaryExpressionOperator::Neq => "!=".to_string(), BinaryExpressionOperator::Lt => "<".to_string(), BinaryExpressionOperator::Gt => ">".to_string(), BinaryExpressionOperator::Leq => "<=".to_string(), BinaryExpressionOperator::Geq => ">=".to_string(), BinaryExpressionOperator::Bol => "!!".to_string(), BinaryExpressionOperator::Inv => "!".to_string(), BinaryExpressionOperator::Rnd => "?".to_string(), } } } pub fn parse_binary_operation(token: &lexer::Token) -> Result { match token { lexer::Token::Not => Ok(BinaryExpressionOperator::Not), lexer::Token::And => Ok(BinaryExpressionOperator::And), lexer::Token::Nand => Ok(BinaryExpressionOperator::Nand), lexer::Token::Or => Ok(BinaryExpressionOperator::Or), lexer::Token::Nor => Ok(BinaryExpressionOperator::Nor), lexer::Token::Xor => Ok(BinaryExpressionOperator::Xor), lexer::Token::Xnor => Ok(BinaryExpressionOperator::Xnor), lexer::Token::Lsh => Ok(BinaryExpressionOperator::Lsh), lexer::Token::Rsh => Ok(BinaryExpressionOperator::Rsh), lexer::Token::Add => Ok(BinaryExpressionOperator::Add), lexer::Token::Sub => Ok(BinaryExpressionOperator::Sub), lexer::Token::Mul => Ok(BinaryExpressionOperator::Mul), lexer::Token::Div => Ok(BinaryExpressionOperator::Div), lexer::Token::Pow => Ok(BinaryExpressionOperator::Pow), lexer::Token::Cmp => Ok(BinaryExpressionOperator::Cmp), lexer::Token::Eq => Ok(BinaryExpressionOperator::Eq), lexer::Token::Neq => Ok(BinaryExpressionOperator::Neq), lexer::Token::Lt => Ok(BinaryExpressionOperator::Lt), lexer::Token::Gt => Ok(BinaryExpressionOperator::Gt), lexer::Token::Leq => Ok(BinaryExpressionOperator::Leq), lexer::Token::Geq => Ok(BinaryExpressionOperator::Geq), lexer::Token::Bol => Ok(BinaryExpressionOperator::Bol), lexer::Token::Inv => Ok(BinaryExpressionOperator::Inv), lexer::Token::Rnd => Ok(BinaryExpressionOperator::Rnd), _ => bail!("Invalid binary expression operator"), } } pub fn parse_binary_expression_arg(tokens: &mut Vec<&lexer::Token>) -> Result { if tokens.is_empty() { bail!("Malformed binary expression"); } let mut args: Vec<_> = tokens.drain(..3).collect(); let mut bin_expr = Arg::BinaryExpression { left: Box::new(parse_args(vec![args[0]])?[0].clone()), right: Box::new(parse_args(vec![args[2]])?[0].clone()), op: parse_binary_operation(args[1])?, }; while !tokens.is_empty() { args = tokens.drain(..2).collect(); bin_expr = Arg::BinaryExpression { left: Box::new(bin_expr), right: Box::new(parse_args(vec![args[1]])?[0].clone()), op: parse_binary_operation(args[0])?, } } Ok(bin_expr) } pub fn parse_args(tokens: Vec<&lexer::Token>) -> Result> { let mut iter = tokens.into_iter(); let mut args: Vec = vec![]; let mut last_was_comma = true; while let Some(token) = iter.next() { match token { lexer::Token::Comma => { last_was_comma = true; } _ => { if !last_was_comma { bail!("Invalid argument separation"); } match token { lexer::Token::Comment(_) => {} lexer::Token::CharLiteral(x) => { let y = unescape_string(x); if y.len() > 1 { bail!("Char cannot hold string") } else if let Some(c) = y.chars().next() { args.push(Arg::Char(c)); } else { bail!("Char cannot be empty"); } } lexer::Token::StringLiteral(x) => { args.push(Arg::String(x.clone())); } lexer::Token::Literal(x) => { args.push(Arg::Variable(x.clone())); } lexer::Token::Number(x) => { args.push(Arg::Number(parse_int::parse(x)?)); } lexer::Token::LParen => { let mut depth: usize = 1; args.push(parse_binary_expression_arg( &mut iter .by_ref() .take_while(|t| match t { lexer::Token::LParen => { depth += 1; true } lexer::Token::RParen => { depth -= 1; depth != 0 } _ => true, }) .collect(), )?); } _ => bail!("Unexpected token for argument"), } last_was_comma = false; } } } Ok(args) } #[cfg(test)] mod tests { use super::*; #[test] fn test_unescape_string() { assert_eq!(unescape_string("\\n test"), "\n test".to_string()); assert_eq!(unescape_string(""), "".to_string()); } }