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 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);
|
||||||
}
|
}
|
|
@ -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)]
|
#[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);
|
||||||
}
|
}
|
Loading…
Reference in New Issue