hence/hence/src/lib/arg.rs

363 lines
13 KiB
Rust

use anyhow::{bail, Result};
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),
Arg::String(x) => format!("\"{}\"", x),
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(match num_parse::parse_uint(x) {
Some(y) => y,
None => bail!("Error parsing number"),
}));
}
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());
}
}