mirror of https://github.com/rm-dr/daisy
Added basic evaluation
parent
8bbe880bd4
commit
1f9bcccab4
141
src/parser.rs
141
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<Token>),
|
||||
|
||||
Root(VecDeque<Token>),
|
||||
Number(LineLocation, f64),
|
||||
Multiply(VecDeque<Token>),
|
||||
Divide(VecDeque<Token>),
|
||||
Add(VecDeque<Token>),
|
||||
Subtract(VecDeque<Token>),
|
||||
Factorial(VecDeque<Token>),
|
||||
Negative(VecDeque<Token>),
|
||||
Power(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.
|
||||
/// The Null operator MUST be equal to zero.
|
||||
|
@ -97,7 +231,8 @@ pub enum ParserError {
|
|||
pub fn parse(s: &String) -> Result<Token, (LineLocation, ParserError)> {
|
||||
|
||||
let mut g: Token = tokenize(s)?;
|
||||
treeify(&mut g)?;
|
||||
|
||||
g = treeify(g)?;
|
||||
g = evaluate(g)?;
|
||||
|
||||
return Ok(g);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -18,9 +18,18 @@ fn get_line_location(t: &Token) -> &LineLocation {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
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<Token, (LineLocation, ParserError)> {
|
||||
|
||||
let g_inner: &mut VecDeque<Token> = 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<Token, (LineLocation, ParserError)> {
|
||||
let mut v: VecDeque<Token> = VecDeque::new();
|
||||
v.push_back(inner_treeify(g)?);
|
||||
g = Token::Root(v);
|
||||
return Ok(g);
|
||||
}
|
Loading…
Reference in New Issue