243 lines
8.2 KiB
Rust
243 lines
8.2 KiB
Rust
use crate::arg;
|
|
use crate::assembler;
|
|
use crate::lexer;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Arg {
|
|
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::String(x) => format!("\"{x}\""),
|
|
Arg::Number(x) => x.to_string(),
|
|
Arg::Variable(x) => x.clone(),
|
|
Arg::BinaryExpression { left, right, op } => {
|
|
format!(
|
|
"({left} {op} {right})",
|
|
left = left.to_code(),
|
|
op = op.to_code(),
|
|
right = right.to_code()
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl assembler::ByteResolvable<assembler::Data> for Arg {
|
|
fn resolve_number(&self, data: &mut assembler::Data) -> Result<u16, String> {
|
|
match self {
|
|
Arg::String(x) => {
|
|
let y = x.replace("\\n", "\n");
|
|
|
|
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.contants.get(&name).cloned();
|
|
|
|
match arg {
|
|
Some(a) => {
|
|
// arg = Some(a.clone());
|
|
match a {
|
|
arg::Arg::Variable(n) => {
|
|
name = n;
|
|
}
|
|
_ => break Ok(a.resolve_number(data).unwrap()),
|
|
};
|
|
}
|
|
_ => return Err(format!("Variable does not exist: '{name}'")),
|
|
}
|
|
}
|
|
}
|
|
Arg::BinaryExpression { left, right, op } => {
|
|
let left_val = left.resolve_number(data).unwrap();
|
|
let right_val = right.resolve_number(data).unwrap();
|
|
|
|
Ok(match op {
|
|
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),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
fn resolve_bytes(&self, data: &mut assembler::Data) -> Result<Vec<u8>, String> {
|
|
match self {
|
|
Arg::String(x) => Ok(x.replace("\\n", "\n").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.contants.get(&name).cloned();
|
|
|
|
match arg {
|
|
Some(a) => {
|
|
// arg = Some(a.clone());
|
|
match a {
|
|
arg::Arg::Variable(n) => {
|
|
name = n;
|
|
}
|
|
_ => break Ok(a.resolve_bytes(data).unwrap()),
|
|
};
|
|
}
|
|
_ => return Err(format!("Variable does not exist: '{name}'")),
|
|
}
|
|
}
|
|
}
|
|
Arg::BinaryExpression {
|
|
left: _,
|
|
right: _,
|
|
op: _,
|
|
} => {
|
|
let x = self.resolve_number(data).unwrap();
|
|
|
|
Ok(vec![(x >> 8) as u8, x as u8])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum BinaryExpressionOperator {
|
|
Add,
|
|
Sub,
|
|
Mul,
|
|
Div,
|
|
Pow,
|
|
}
|
|
|
|
impl assembler::ToCode for BinaryExpressionOperator {
|
|
fn to_code(&self) -> String {
|
|
match self {
|
|
BinaryExpressionOperator::Add => "+".to_string(),
|
|
BinaryExpressionOperator::Sub => "-".to_string(),
|
|
BinaryExpressionOperator::Mul => "*".to_string(),
|
|
BinaryExpressionOperator::Div => "/".to_string(),
|
|
BinaryExpressionOperator::Pow => "**".to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn parse_binary_operation(token: &lexer::Token) -> Result<BinaryExpressionOperator, String> {
|
|
match token {
|
|
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),
|
|
_ => Err("Invalid binary expression operator".to_string()),
|
|
}
|
|
}
|
|
|
|
pub fn parse_binary_expression_arg(tokens: &mut Vec<&&lexer::Token>) -> Result<Arg, String> {
|
|
if tokens.is_empty() {
|
|
return Err("Malformed binary expression".to_string());
|
|
}
|
|
|
|
let mut args: Vec<&&lexer::Token> = tokens.drain(..3).collect();
|
|
|
|
let mut bin_expr = Arg::BinaryExpression {
|
|
left: Box::new((&parse_args(vec![args[0]]).unwrap()[0]).clone()),
|
|
right: Box::new((&parse_args(vec![args[2]]).unwrap()[0]).clone()),
|
|
op: parse_binary_operation(args[1]).unwrap(),
|
|
};
|
|
|
|
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]]).unwrap()[0]).clone()),
|
|
op: parse_binary_operation(args[0]).unwrap(),
|
|
}
|
|
}
|
|
|
|
Ok(bin_expr)
|
|
}
|
|
|
|
pub fn parse_args(tokens: Vec<&lexer::Token>) -> Result<Vec<Arg>, &str> {
|
|
let mut iter = tokens.iter();
|
|
let mut args: Vec<Arg> = Vec::new();
|
|
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 {
|
|
return Err("Invalid argument separation");
|
|
}
|
|
|
|
match token {
|
|
lexer::Token::Comment(_) => {}
|
|
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,
|
|
_ => return Err("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(),
|
|
)
|
|
.unwrap(),
|
|
);
|
|
}
|
|
_ => return Err("Unexpected token for argument"),
|
|
}
|
|
|
|
last_was_comma = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(args)
|
|
}
|