use crate::{MexeError, Operator, Result, Token};
pub(crate) fn parse_and_evaluate(input: Vec<Token>) -> Result<f64> {
match ll_parse_expr(&input[..]) {
Ok((Some(val), input)) => {
if !is_over(input) {
Err(MexeError::UnexpectedToken(input[0].to_string()))
} else {
Ok(val)
}
}
Ok((None, _)) => Err(MexeError::InternalParserError),
Err(err) => Err(err),
}
}
fn is_over(input: &[Token]) -> bool {
input.len() == 1 && input[0] == Token::EOI
}
fn ll_parse_expr(input: &[Token]) -> Result<(Option<f64>, &[Token])> {
match input[0] {
Token::LPar | Token::Number(_) | Token::Op(Operator::Minus) => {
let (val, input) = ll_parse_term(input)?;
ll_parse_addexpr(val.unwrap(), input)
}
token => Err(MexeError::UnexpectedToken(token.to_string())),
}
}
fn ll_parse_addexpr(val: f64, input: &[Token]) -> Result<(Option<f64>, &[Token])> {
match &input[0] {
t @ (Token::Op(Operator::Plus) | Token::Op(Operator::Minus)) => {
let (val2, input) = ll_parse_term(&input[1..])?;
let val = match t {
Token::Op(Operator::Plus) => val + val2.unwrap(),
Token::Op(Operator::Minus) => val - val2.unwrap(),
_ => unreachable!(),
};
ll_parse_addexpr(val, input)
}
_ => Ok((Some(val), input)),
}
}
fn ll_parse_term(input: &[Token]) -> Result<(Option<f64>, &[Token])> {
match input[0] {
Token::LPar | Token::Number(_) | Token::Op(Operator::Minus) => {
let (val, input) = ll_parse_factor(input)?;
ll_parse_multerm(val.unwrap(), input)
}
token => Err(MexeError::UnexpectedToken(token.to_string())),
}
}
fn ll_parse_multerm(val: f64, input: &[Token]) -> Result<(Option<f64>, &[Token])> {
match &input[0] {
t @ (Token::Op(Operator::Mul) | Token::Op(Operator::Div)) => {
let (val2, input) = ll_parse_factor(&input[1..])?;
let val = match t {
Token::Op(Operator::Mul) => val * val2.unwrap(),
Token::Op(Operator::Div) => val / val2.unwrap(),
_ => unreachable!(),
};
ll_parse_multerm(val, input)
}
_ => Ok((Some(val), input)),
}
}
fn ll_parse_factor(input: &[Token]) -> Result<(Option<f64>, &[Token])> {
match (&input[0], input.get(1)) {
(Token::Op(Operator::Minus), Some(Token::LPar)) => match ll_parse_expr(&input[2..]) {
Ok((Some(val), input)) => ll_consume_rpar(-val, input),
err => err,
},
(Token::Op(Operator::Minus), Some(Token::Number(n))) => Ok((Some(-*n), &input[2..])),
(Token::LPar, _) => match ll_parse_expr(&input[1..]) {
Ok((Some(val), input)) => ll_consume_rpar(val, input),
err => err,
},
(Token::Number(n), _) => Ok((Some(*n), &input[1..])),
(token, _) => Err(MexeError::UnexpectedToken(token.to_string())),
}
}
fn ll_consume_rpar(val: f64, input: &[Token]) -> Result<(Option<f64>, &[Token])> {
match input.get(0) {
Some(Token::RPar) => Ok((Some(val), &input[1..])),
None => Err(MexeError::UnexpectEndOfInput),
Some(t) => Err(MexeError::UnexpectedToken(t.to_string())),
}
}