361 lines
13 KiB
Rust
361 lines
13 KiB
Rust
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<Self>,
|
|
right: Box<Self>,
|
|
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<assembler::Data> for Arg {
|
|
fn resolve_number(&self, data: &mut assembler::Data) -> Result<u16> {
|
|
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<arg::Arg>;
|
|
|
|
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<Vec<u8>> {
|
|
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<arg::Arg>;
|
|
|
|
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<String> {
|
|
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<BinaryExpressionOperator> {
|
|
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<Arg> {
|
|
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<Vec<Arg>> {
|
|
let mut iter = tokens.into_iter();
|
|
let mut args: Vec<Arg> = 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());
|
|
}
|
|
}
|