use crate::{
ast::{Args, Evaluate, EvaluationResult, Node, Root, Scope},
error::Error,
lexer::tokenize,
tokens::{Operator, Token, TokenList},
};
use std::{collections::VecDeque, string::ToString};
type NodeList = Vec<Node>;
pub fn eval(expr: &str, scope: &Scope) -> EvaluationResult {
parse_tokens(tokenize(expr, scope)?, scope)?.eval()
}
pub fn compile<'a>(expr: &'a str, scope: &'a Scope) -> Result<Root<'a>, Error> {
parse_tokens(tokenize(expr, scope)?, scope)
}
fn encounter_func(f: String, operands: &mut NodeList) -> Result<(), Error> {
let mut args = Args::with_capacity(2);
args.push_front(
operands
.pop()
.ok_or(Error::NotEnoughFunctionParams(f.clone()))?,
);
while let Some(last) = operands.pop() {
if last.token != Token::Comma {
operands.push(last);
break;
}
else {
args.push_front(
operands
.pop()
.ok_or(Error::FunctionSyntaxError(f.clone()))?,
);
}
}
operands.push(Node::new(Token::Function(f), Some(args)));
Ok(())
}
fn right_paren(
operators: &mut TokenList,
operands: &mut NodeList,
) -> Result<(), Error> {
while let Some(top) = operators.pop() {
match top {
Token::LeftParenthesis => match operators.last() {
Some(Token::Function(_)) => {},
_ => break,
},
Token::Function(f) => encounter_func(f, operands)?,
Token::Operator(op) => add_operator(op, operands)?,
_ => {},
}
}
Ok(())
}
fn add_operator(
operator: Operator,
operands: &mut NodeList,
) -> Result<(), Error> {
let num_operands = operator.num_operands();
let mut args: VecDeque<Node> =
VecDeque::with_capacity(num_operands as usize);
for _ in 0..num_operands {
args.push_front(
operands
.pop()
.ok_or(Error::MissingOperands(operator.to_string()))?,
);
}
operands.push(Node::new(Token::Operator(operator), Some(args)));
Ok(())
}
fn encounter_operator(
cur_operator: Operator,
operators: &mut TokenList,
operands: &mut NodeList,
) -> Result<(), Error> {
while let Some(top) = operators.pop() {
match top {
Token::Operator(top_operator) => {
if top_operator > cur_operator
|| (top_operator == cur_operator
&& !cur_operator.is_right_associative())
{
add_operator(top_operator, operands)?
}
else {
operators.push(Token::Operator(top_operator));
break;
}
},
Token::Function(f) => encounter_func(f, operands)?,
_ => {
operators.push(top);
break;
},
}
}
operators.push(Token::Operator(cur_operator));
Ok(())
}
fn parse_tokens(tokens: TokenList, scope: &Scope) -> Result<Root, Error> {
let mut operators: TokenList = Vec::new();
let mut operands: NodeList = Vec::new();
for token in tokens {
match token {
Token::Number(num) => operands.push(Node {
token: Token::Number(num),
args: None,
}),
Token::Variable(var) => operands.push(Node {
token: Token::Variable(var),
args: None,
}),
Token::RightParenthesis => {
right_paren(&mut operators, &mut operands)?
},
Token::LeftParenthesis => operators.push(token),
Token::Operator(op1) => {
encounter_operator(op1, &mut operators, &mut operands)?;
},
Token::Function(f) => operators.push(Token::Function(f)),
Token::Comma => operands.push(Node::new(token, None)),
};
}
while let Some(Token::Operator(operator)) = operators.pop() {
add_operator(operator, &mut operands)?
}
operands.pop().map_or_else(
|| Err(Error::EmptyExpression),
|node| Ok(Root { node, scope }),
)
}