use std::env::args; use parser::{ParseNode, Parser}; use testing::tokenize_str; use tokenizer::Tokenizer; use tuker::*; // cargo run --example calculator "1 + 1" fn main() { let args: Vec<_> = args().collect(); let table_input = " [tokenizer] number = '[0-9]+' plus = '[+]' minus = '[-]' times = '[*]' div = '[/]' [parser] main = 'expr' expr = 'as_expr' as_expr = '(md_expr (as_oper md_expr)*)' as_oper = '[plus minus]' md_expr = '(number (md_oper number)*)' md_oper = '[times div]' "; let table_input = &table_input.replace("'", "\""); let input_text = args .get(1) .expect("Please provide the string to be evaluated"); let tokenizer = &Tokenizer::from_toml(&table_input).expect("Couldn't deserialize test tokenizer"); let tokens = tokenize_str(&table_input, &input_text, false); let parser = &Parser::from_toml(&table_input, tokenizer).expect("Couldn't deserialize test parser"); let node = parser.parse_tokens("main", &tokens, tokenizer); // let node = dbg!(node); println!("{}", eval_expr(&node.unwrap())); } fn eval_expr(node: &ParseNode) -> f64 { eval_as_expr(node.find("as_expr").unwrap()) } enum As { Plus, Minus, } enum Md { Times, Div, } fn eval_as_expr(node: &ParseNode) -> f64 { let mut nums = node.find_all("md_expr"); let mut res: f64 = eval_md_expr(nums.next().unwrap()); let rest_nums: Vec<_> = nums.collect(); let mut opers = node.find_all("as_oper").map(|a| { if let Some(_) = a.find("plus") { As::Plus } else { As::Minus } }); for i in 0..rest_nums.len() { let new_num: f64 = eval_md_expr(rest_nums[i]); match opers.next().unwrap() { As::Plus => res += new_num, As::Minus => res -= new_num, } } res } fn eval_md_expr(node: &ParseNode) -> f64 { let mut nums = node.find_all("number"); let mut res: f64 = nums.next().unwrap().content().parse().unwrap(); let rest_nums: Vec<_> = nums.collect(); let mut opers = node.find_all("md_oper").map(|a| { if let Some(_) = a.find("times") { Md::Times } else { Md::Div } }); for i in 0..rest_nums.len() { let new_num: f64 = rest_nums[i].content().parse().unwrap(); match opers.next().unwrap() { Md::Times => res *= new_num, Md::Div => res /= new_num, } } res }