From 1f9bcccab438225a370fd67c29d822e0eb55f1db Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 24 Mar 2023 13:16:58 -0700 Subject: [PATCH] Added basic evaluation --- src/parser.rs | 141 ++++++++++++++++++++++++++++++++++++++++- src/parser/evaluate.rs | 95 +++++++++++++++++++++++++++ src/parser/treeify.rs | 44 +++++++++---- 3 files changed, 264 insertions(+), 16 deletions(-) create mode 100644 src/parser/evaluate.rs diff --git a/src/parser.rs b/src/parser.rs index a884239..7e1d48e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,10 @@ mod tokenize; mod treeify; +mod evaluate; use crate::parser::tokenize::tokenize; use crate::parser::treeify::treeify; +use crate::parser::evaluate::evaluate; use std::collections::VecDeque; @@ -11,6 +13,11 @@ use std::collections::VecDeque; /// /// Tokens starting with `Pre*` are intermediate tokens, and /// will never show up in a fully-parsed expression tree. + +pub trait Eval { + fn eval(&self) -> Token; +} + #[derive(Debug)] pub enum Token { @@ -30,17 +37,144 @@ pub enum Token { /// PreGroups aren't needed once we have a tree. PreGroup(LineLocation, VecDeque), + Root(VecDeque), Number(LineLocation, f64), Multiply(VecDeque), Divide(VecDeque), Add(VecDeque), - Subtract(VecDeque), Factorial(VecDeque), Negative(VecDeque), Power(VecDeque), Modulo(VecDeque), } +impl Eval for Token { + fn eval(&self) -> Token { + match self { + Token::Negative(ref v) => { + if v.len() != 1 {panic!()}; + + if let Token::Number(l, v) = v[0]{ + Token::Number(l, -v) + } else { panic!(); } + }, + + Token::Add(ref v) => { + let mut sum: f64 = 0f64; + let mut new_pos: usize = 0; + let mut new_len: usize = 0; + for i in v.iter() { + if let Token::Number(l, v) = i { + let LineLocation{pos, len} = *l; + if new_pos == 0 {new_pos = pos}; + new_len = new_len + len; + sum += v; + } else { + panic!(); + } + } + + Token::Number( + LineLocation { pos: new_pos, len: new_len }, + sum + ) + }, + + Token::Multiply(ref v) => { + let mut prod: f64 = 1f64; + let mut new_pos: usize = 0; + let mut new_len: usize = 0; + for i in v.iter() { + if let Token::Number(l, v) = i { + let LineLocation{pos, len} = *l; + if new_pos == 0 {new_pos = pos}; + new_len = new_len + len; + prod *= v; + } else { + panic!(); + } + } + + Token::Number( + LineLocation { pos: new_pos, len: new_len }, + prod + ) + }, + + Token::Divide(ref v) => { + if v.len() != 2 {panic!()}; + let a = &v[0]; + let b = &v[1]; + + if let Token::Number(la, va) = a { + if let Token::Number(lb, vb) = b { + let LineLocation{pos: posa, ..} = *la; + let LineLocation{pos: posb, len: lenb} = lb; + Token::Number( + LineLocation { pos: posa, len: posb - posa + lenb }, + va/vb + ) + } else { panic!(); } + } else { panic!(); } + }, + + Token::Modulo(ref v) => { + if v.len() != 2 {panic!()}; + let a = &v[0]; + let b = &v[1]; + + if let Token::Number(la, va) = a { + if let Token::Number(lb, vb) = b { + let LineLocation{pos: posa, ..} = *la; + let LineLocation{pos: posb, len: lenb} = lb; + Token::Number( + LineLocation { pos: posa, len: posb - posa + lenb }, + va%vb + ) + } else { panic!(); } + } else { panic!(); } + }, + + Token::Power(ref v) => { + if v.len() != 2 {panic!()}; + let a = &v[0]; + let b = &v[1]; + + if let Token::Number(la, va) = a { + if let Token::Number(lb, vb) = b { + let LineLocation{pos: posa, ..} = *la; + let LineLocation{pos: posb, len: lenb} = lb; + Token::Number( + LineLocation { pos: posa, len: posb - posa + lenb }, + va.powf(*vb) + ) + } else { panic!(); } + } else { panic!(); } + }, + + Token::Root(ref v) => { + if v.len() != 2 {panic!()}; + let a = &v[0]; + let b = &v[1]; + + if let Token::Number(la, va) = a { + if let Token::Number(lb, vb) = b { + let LineLocation{pos: posa, ..} = *la; + let LineLocation{pos: posb, len: lenb} = lb; + Token::Number( + LineLocation { pos: posa, len: posb - posa + lenb }, + va.powf(1f64 / *vb) + ) + } else { panic!(); } + } else { panic!(); } + }, + + Token::Factorial(ref v) => { todo!() }, + _ => panic!() + } + } +} + /// Operator types, in order of increasing priority. /// The Null operator MUST be equal to zero. @@ -97,7 +231,8 @@ pub enum ParserError { pub fn parse(s: &String) -> Result { let mut g: Token = tokenize(s)?; - treeify(&mut g)?; - + g = treeify(g)?; + g = evaluate(g)?; + return Ok(g); } \ No newline at end of file diff --git a/src/parser/evaluate.rs b/src/parser/evaluate.rs new file mode 100644 index 0000000..9c9b5a7 --- /dev/null +++ b/src/parser/evaluate.rs @@ -0,0 +1,95 @@ +use std::collections::VecDeque; + +use crate::parser::Token; +use crate::parser::Eval; +use crate::parser::LineLocation; +use crate::parser::ParserError; + +fn get_at_coords<'a>(g: &'a mut Token, coords: &Vec) -> &'a mut Token { + let mut h = &mut *g; + + for t in coords.iter() { + let inner = match h { + Token::Multiply(ref mut v) => v, + Token::Divide(ref mut v) => v, + Token::Add(ref mut v) => v, + Token::Factorial(ref mut v) => v, + Token::Negative(ref mut v) => v, + Token::Power(ref mut v) => v, + Token::Modulo(ref mut v) => v, + Token::Root(ref mut v) => v, + _ => panic!() + }; + + h = &mut inner[*t]; + } + + return h; +} + + +pub fn evaluate( + mut g: Token, +) -> Result { + + let mut coords: Vec = Vec::with_capacity(16); + coords.push(0); + + 'outer: loop { + + let mut h = &mut g; + for t in coords.iter() { + let inner = match h { + Token::Multiply(ref mut v) => v, + Token::Divide(ref mut v) => v, + Token::Add(ref mut v) => v, + Token::Factorial(ref mut v) => v, + Token::Negative(ref mut v) => v, + Token::Power(ref mut v) => v, + Token::Modulo(ref mut v) => v, + Token::Root(ref mut v) => v, + _ => panic!() + }; + + if *t >= inner.len() { + coords.pop(); + if coords.len() == 0 { break 'outer; } + + + let p = get_at_coords(&mut g, &coords); + let e = p.eval(); + *p = e; + + let l = coords.pop().unwrap(); + coords.push(l + 1); + continue 'outer; + } + + h = &mut inner[*t]; + } + + match h { + Token::Multiply(v) | + Token::Divide(v) | + Token::Add(v) | + Token::Factorial(v) | + Token::Negative(v) | + Token::Power(v) | + Token::Modulo(v) + => { + coords.push(0); + continue 'outer; + }, + + Token::Number(_,_) => { + let l = coords.pop().unwrap(); + coords.push(l + 1); + continue 'outer; + } + _ => panic!() + }; + } + + + return Ok(g); +} \ No newline at end of file diff --git a/src/parser/treeify.rs b/src/parser/treeify.rs index a5a578b..6c9dd2d 100644 --- a/src/parser/treeify.rs +++ b/src/parser/treeify.rs @@ -18,9 +18,18 @@ fn get_line_location(t: &Token) -> &LineLocation { } #[inline(always)] -fn select_op(k: Operators, new_token_args: VecDeque) -> Token { +fn select_op(k: Operators, mut new_token_args: VecDeque) -> Token { match k { - Operators::Subtract => Token::Subtract(new_token_args), + Operators::Subtract => { + let a = new_token_args.pop_front().unwrap(); + let b = new_token_args.pop_front().unwrap(); + + Token::Add( + VecDeque::from(vec!( + a, + Token::Negative(VecDeque::from(vec!(b))) + ))) + }, Operators::Add => Token::Add(new_token_args), Operators::Divide => Token::Divide(new_token_args), Operators::Multiply => Token::Multiply(new_token_args), @@ -114,8 +123,8 @@ fn treeify_binary( let mut left = g_inner.remove(i-1).unwrap(); let this = g_inner.remove(i-1).unwrap(); let mut right = g_inner.remove(i-1).unwrap(); - if let Token::PreGroup(_, _) = right { treeify(&mut right)?; } - if let Token::PreGroup(_, _) = left { treeify(&mut left)?; } + if let Token::PreGroup(_, _) = right { right = inner_treeify(right)?; } + if let Token::PreGroup(_, _) = left { left = inner_treeify(left)?; } let k = match this { Token::PreOperator(_, k) => k, @@ -209,7 +218,7 @@ fn treeify_unaryleft( if right_val.is_none() || this_val > right_val.unwrap() { let this = g_inner.remove(i).unwrap(); let mut right = g_inner.remove(i).unwrap(); - if let Token::PreGroup(_, _) = right { treeify(&mut right)?; } + if let Token::PreGroup(_, _) = right { right = inner_treeify(right)?; } let k = match this { Token::PreOperator(_, k) => k, @@ -309,7 +318,7 @@ fn treeify_unaryright( if left_val.is_none() || this_val > left_val.unwrap() { let this = g_inner.remove(i).unwrap(); let mut left = g_inner.remove(i-1).unwrap(); - if let Token::PreGroup(_, _) = left { treeify(&mut left)?; } + if let Token::PreGroup(_, _) = left { left = inner_treeify(left)?; } let k = match this { Token::PreOperator(_, k) => k, @@ -332,9 +341,9 @@ fn treeify_unaryright( }; } -pub fn treeify( - g: &mut Token, -) -> Result<(), (LineLocation, ParserError)> { +fn inner_treeify( + mut g: Token, +) -> Result { let g_inner: &mut VecDeque = match g { Token::PreGroup(_, ref mut x) => x, @@ -368,19 +377,28 @@ pub fn treeify( }; } - *g = g_inner.pop_front().unwrap(); + g = g_inner.pop_front().unwrap(); // Catch the edge case where the entire group we're given // consists of one operator. This is always a syntax error. match g { Token::PreOperator(l, _) => { - return Err((*l, ParserError::Syntax)); + return Err((l, ParserError::Syntax)); }, Token::PreGroup(_,_) => { - treeify(g)?; + g = treeify(g)?; } _ => {} }; - return Ok(()); + return Ok(g); +} + +pub fn treeify( + mut g: Token, +) -> Result { + let mut v: VecDeque = VecDeque::new(); + v.push_back(inner_treeify(g)?); + g = Token::Root(v); + return Ok(g); } \ No newline at end of file