Added basic evaluation

pull/2/head
Mark 2023-03-24 13:16:58 -07:00
parent 8bbe880bd4
commit 1f9bcccab4
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
3 changed files with 264 additions and 16 deletions

View File

@ -1,8 +1,10 @@
mod tokenize; mod tokenize;
mod treeify; mod treeify;
mod evaluate;
use crate::parser::tokenize::tokenize; use crate::parser::tokenize::tokenize;
use crate::parser::treeify::treeify; use crate::parser::treeify::treeify;
use crate::parser::evaluate::evaluate;
use std::collections::VecDeque; use std::collections::VecDeque;
@ -11,6 +13,11 @@ use std::collections::VecDeque;
/// ///
/// Tokens starting with `Pre*` are intermediate tokens, and /// Tokens starting with `Pre*` are intermediate tokens, and
/// will never show up in a fully-parsed expression tree. /// will never show up in a fully-parsed expression tree.
pub trait Eval {
fn eval(&self) -> Token;
}
#[derive(Debug)] #[derive(Debug)]
pub enum Token { pub enum Token {
@ -30,17 +37,144 @@ pub enum Token {
/// PreGroups aren't needed once we have a tree. /// PreGroups aren't needed once we have a tree.
PreGroup(LineLocation, VecDeque<Token>), PreGroup(LineLocation, VecDeque<Token>),
Root(VecDeque<Token>),
Number(LineLocation, f64), Number(LineLocation, f64),
Multiply(VecDeque<Token>), Multiply(VecDeque<Token>),
Divide(VecDeque<Token>), Divide(VecDeque<Token>),
Add(VecDeque<Token>), Add(VecDeque<Token>),
Subtract(VecDeque<Token>),
Factorial(VecDeque<Token>), Factorial(VecDeque<Token>),
Negative(VecDeque<Token>), Negative(VecDeque<Token>),
Power(VecDeque<Token>), Power(VecDeque<Token>),
Modulo(VecDeque<Token>), Modulo(VecDeque<Token>),
} }
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. /// Operator types, in order of increasing priority.
/// The Null operator MUST be equal to zero. /// The Null operator MUST be equal to zero.
@ -97,7 +231,8 @@ pub enum ParserError {
pub fn parse(s: &String) -> Result<Token, (LineLocation, ParserError)> { pub fn parse(s: &String) -> Result<Token, (LineLocation, ParserError)> {
let mut g: Token = tokenize(s)?; let mut g: Token = tokenize(s)?;
treeify(&mut g)?; g = treeify(g)?;
g = evaluate(g)?;
return Ok(g); return Ok(g);
} }

95
src/parser/evaluate.rs Normal file
View File

@ -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<usize>) -> &'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<Token, (LineLocation, ParserError)> {
let mut coords: Vec<usize> = 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);
}

View File

@ -18,9 +18,18 @@ fn get_line_location(t: &Token) -> &LineLocation {
} }
#[inline(always)] #[inline(always)]
fn select_op(k: Operators, new_token_args: VecDeque<Token>) -> Token { fn select_op(k: Operators, mut new_token_args: VecDeque<Token>) -> Token {
match k { 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::Add => Token::Add(new_token_args),
Operators::Divide => Token::Divide(new_token_args), Operators::Divide => Token::Divide(new_token_args),
Operators::Multiply => Token::Multiply(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 mut left = g_inner.remove(i-1).unwrap();
let this = g_inner.remove(i-1).unwrap(); let this = g_inner.remove(i-1).unwrap();
let mut right = 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(_, _) = right { right = inner_treeify(right)?; }
if let Token::PreGroup(_, _) = left { treeify(&mut left)?; } if let Token::PreGroup(_, _) = left { left = inner_treeify(left)?; }
let k = match this { let k = match this {
Token::PreOperator(_, k) => k, Token::PreOperator(_, k) => k,
@ -209,7 +218,7 @@ fn treeify_unaryleft(
if right_val.is_none() || this_val > right_val.unwrap() { if right_val.is_none() || this_val > right_val.unwrap() {
let this = g_inner.remove(i).unwrap(); let this = g_inner.remove(i).unwrap();
let mut right = 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 { let k = match this {
Token::PreOperator(_, k) => k, Token::PreOperator(_, k) => k,
@ -309,7 +318,7 @@ fn treeify_unaryright(
if left_val.is_none() || this_val > left_val.unwrap() { if left_val.is_none() || this_val > left_val.unwrap() {
let this = g_inner.remove(i).unwrap(); let this = g_inner.remove(i).unwrap();
let mut left = g_inner.remove(i-1).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 { let k = match this {
Token::PreOperator(_, k) => k, Token::PreOperator(_, k) => k,
@ -332,9 +341,9 @@ fn treeify_unaryright(
}; };
} }
pub fn treeify( fn inner_treeify(
g: &mut Token, mut g: Token,
) -> Result<(), (LineLocation, ParserError)> { ) -> Result<Token, (LineLocation, ParserError)> {
let g_inner: &mut VecDeque<Token> = match g { let g_inner: &mut VecDeque<Token> = match g {
Token::PreGroup(_, ref mut x) => x, 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 // Catch the edge case where the entire group we're given
// consists of one operator. This is always a syntax error. // consists of one operator. This is always a syntax error.
match g { match g {
Token::PreOperator(l, _) => { Token::PreOperator(l, _) => {
return Err((*l, ParserError::Syntax)); return Err((l, ParserError::Syntax));
}, },
Token::PreGroup(_,_) => { Token::PreGroup(_,_) => {
treeify(g)?; g = treeify(g)?;
} }
_ => {} _ => {}
}; };
return Ok(()); return Ok(g);
}
pub fn treeify(
mut g: Token,
) -> Result<Token, (LineLocation, ParserError)> {
let mut v: VecDeque<Token> = VecDeque::new();
v.push_back(inner_treeify(g)?);
g = Token::Root(v);
return Ok(g);
} }