mirror of https://github.com/rm-dr/daisy
Added square root, fixed many parser bugs
parent
6db5137b56
commit
71d9aaa039
|
@ -43,14 +43,14 @@ pub fn evaluate(
|
|||
}
|
||||
|
||||
match h {
|
||||
Token::Operator(_,_,_)
|
||||
Token::Operator(_,_)
|
||||
=> {
|
||||
coords.push(0);
|
||||
continue 'outer;
|
||||
},
|
||||
|
||||
Token::Constant(_,_,_) |
|
||||
Token::Number(_,_) => {
|
||||
Token::Constant(_,_) |
|
||||
Token::Number(_) => {
|
||||
let l = coords.pop().unwrap();
|
||||
coords.push(l + 1);
|
||||
continue 'outer;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use crate::parser::PreToken;
|
||||
use crate::tokens::LineLocation;
|
||||
use crate::parser::LineLocation;
|
||||
|
||||
|
||||
pub(in crate::parser) fn find_subs(
|
||||
|
@ -64,7 +64,10 @@ pub(in crate::parser) fn find_subs(
|
|||
"chi" => {Some("χ")},
|
||||
"psi" => {Some("ψ")},
|
||||
"omega" => {Some("ω")},
|
||||
|
||||
// Operators
|
||||
"sqrt" => {Some("√")},
|
||||
"rt" => {Some("√")},
|
||||
|
||||
_ => {None}
|
||||
};
|
||||
|
|
|
@ -1,16 +1,28 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use crate::tokens::LineLocation;
|
||||
use crate::tokens::Operator;
|
||||
use crate::parser::PreToken;
|
||||
|
||||
use crate::parser::LineLocation;
|
||||
use crate::parser::ParserError;
|
||||
|
||||
use crate::tokens::Operator;
|
||||
|
||||
// Inserts implicit operators
|
||||
fn lookback(
|
||||
g: &mut VecDeque<PreToken>
|
||||
) -> Result<(), (LineLocation, ParserError)> {
|
||||
if g.len() >= 2 {
|
||||
if g.len() == 1 {
|
||||
let a: PreToken = g.pop_back().unwrap();
|
||||
match &a {
|
||||
PreToken::PreOperator(l,o)
|
||||
=> {
|
||||
if o == "-" {
|
||||
g.push_back(PreToken::PreOperator(*l, String::from("neg")));
|
||||
} else { g.push_back(a); }
|
||||
},
|
||||
_ => { g.push_back(a); }
|
||||
};
|
||||
|
||||
} else {
|
||||
let b: PreToken = g.pop_back().unwrap();
|
||||
let a: PreToken = g.pop_back().unwrap();
|
||||
|
||||
|
@ -42,10 +54,58 @@ fn lookback(
|
|||
));
|
||||
}
|
||||
|
||||
// The following are fine
|
||||
(PreToken::PreOperator(_,_), _) |
|
||||
(_, PreToken::PreOperator(_,_))
|
||||
=> { g.push_back(a); g.push_back(b); },
|
||||
(PreToken::PreOperator(_, sa), PreToken::PreOperator(l,sb))
|
||||
=> {
|
||||
if sb == "-" && {
|
||||
let o = Operator::from_string(sa);
|
||||
|
||||
o.is_some() &&
|
||||
(
|
||||
o.unwrap().is_binary() ||
|
||||
!o.unwrap().is_left_associative()
|
||||
)
|
||||
} {
|
||||
g.push_back(a);
|
||||
g.push_back(PreToken::PreOperator(*l, String::from("neg")));
|
||||
} else { g.push_back(a); g.push_back(b); }
|
||||
}
|
||||
|
||||
// Insert implicit multiplications for unary operators
|
||||
(PreToken::PreNumber(_,_), PreToken::PreOperator(l,s))
|
||||
| (PreToken::PreGroup(_,_), PreToken::PreOperator(l,s))
|
||||
| (PreToken::PreWord(_,_), PreToken::PreOperator(l,s))
|
||||
=> {
|
||||
let o = Operator::from_string(s);
|
||||
g.push_back(a);
|
||||
if o.is_some() {
|
||||
let o = o.unwrap();
|
||||
if (!o.is_binary()) && (!o.is_left_associative()) {
|
||||
g.push_back(PreToken::PreOperator(
|
||||
LineLocation{pos: l.pos-1, len: 0},
|
||||
String::from("i*")
|
||||
));
|
||||
}
|
||||
}
|
||||
g.push_back(b);
|
||||
},
|
||||
|
||||
(PreToken::PreOperator(_,s), PreToken::PreNumber(l,_))
|
||||
| (PreToken::PreOperator(_,s), PreToken::PreGroup(l,_))
|
||||
| (PreToken::PreOperator(_,s), PreToken::PreWord(l,_))
|
||||
=> {
|
||||
let o = Operator::from_string(s);
|
||||
g.push_back(a);
|
||||
if o.is_some() {
|
||||
let o = o.unwrap();
|
||||
if (!o.is_binary()) && o.is_left_associative() {
|
||||
g.push_back(PreToken::PreOperator(
|
||||
LineLocation{pos: l.pos-1, len: 0},
|
||||
String::from("i*")
|
||||
));
|
||||
}
|
||||
}
|
||||
g.push_back(b);
|
||||
},
|
||||
|
||||
// This shouldn't ever happen.
|
||||
(PreToken::PreGroupStart(_), _)
|
||||
|
@ -102,16 +162,6 @@ pub(in crate::parser) fn groupify(
|
|||
lookback(v_now)?;
|
||||
},
|
||||
|
||||
PreToken::PreWord(ref l, ref s) => {
|
||||
let o = Operator::from_string(&s[..]);
|
||||
if o.is_some() {
|
||||
v_now.push_back(PreToken::PreOperator(*l, s.clone()));
|
||||
} else {
|
||||
v_now.push_back(t);
|
||||
}
|
||||
lookback(v_now)?;
|
||||
}
|
||||
|
||||
_ => {
|
||||
v_now.push_back(t);
|
||||
lookback(v_now)?;
|
||||
|
|
|
@ -12,9 +12,17 @@ use crate::parser::groupify::groupify;
|
|||
use crate::parser::treeify::treeify;
|
||||
use crate::parser::find_subs::find_subs;
|
||||
|
||||
use crate::tokens::LineLocation;
|
||||
use crate::tokens::Token;
|
||||
|
||||
/// Specifies the location of a token in an input string.
|
||||
/// Used to locate ParserErrors.
|
||||
#[derive(Debug)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct LineLocation {
|
||||
pub pos: usize,
|
||||
pub len: usize
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum PreToken {
|
||||
PreNumber(LineLocation, String),
|
||||
|
@ -67,14 +75,14 @@ impl PreToken {
|
|||
Ok(n) => n,
|
||||
Err(_) => return Err((l, ParserError::BadNumber))
|
||||
};
|
||||
return Ok(Token::Number(l, n));
|
||||
return Ok(Token::Number(n));
|
||||
},
|
||||
PreToken::PreWord(l, s) => {
|
||||
return Ok(match &s[..] {
|
||||
// Mathematical constants
|
||||
"π"|"pi" => { Token::Constant(l, 3.141592653, String::from("pi")) },
|
||||
"e" => { Token::Constant(l, 2.71828, String::from("e")) },
|
||||
"phi"|"φ" => { Token::Constant(l, 1.61803, String::from("phi")) },
|
||||
"π"|"pi" => { Token::Constant(3.141592653, String::from("pi")) },
|
||||
"e" => { Token::Constant(2.71828, String::from("e")) },
|
||||
"phi"|"φ" => { Token::Constant(1.61803, String::from("phi")) },
|
||||
_ => { return Err((l, ParserError::Undefined(s))); }
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,28 +1,44 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use crate::parser::PreToken;
|
||||
use crate::tokens::LineLocation;
|
||||
use crate::parser::LineLocation;
|
||||
|
||||
/// Updates the length of a Token's LineLocation.
|
||||
/// Run whenever a token is finished.
|
||||
use crate::tokens::Operator;
|
||||
|
||||
// Called whenever a token is finished.
|
||||
#[inline(always)]
|
||||
fn update_line_location(mut t: PreToken, stop_i: usize) -> PreToken {
|
||||
fn push_token(g: &mut VecDeque<PreToken>, t: Option<PreToken>, stop_i: usize) {
|
||||
|
||||
if t.is_none() { return }
|
||||
let mut t = t.unwrap();
|
||||
|
||||
match t {
|
||||
PreToken::PreGroupStart(ref mut l) |
|
||||
PreToken::PreGroupEnd(ref mut l) |
|
||||
PreToken::PreOperator(ref mut l, _) |
|
||||
PreToken::PreNumber(ref mut l, _) |
|
||||
PreToken::PreWord(ref mut l, _)
|
||||
PreToken::PreGroupStart(ref mut l)
|
||||
| PreToken::PreGroupEnd(ref mut l)
|
||||
| PreToken::PreOperator(ref mut l, _)
|
||||
| PreToken::PreNumber(ref mut l, _)
|
||||
| PreToken::PreWord(ref mut l, _)
|
||||
=> {
|
||||
*l = LineLocation{
|
||||
pos: l.pos,
|
||||
len: stop_i - l.pos,
|
||||
};
|
||||
},
|
||||
_ => panic!()
|
||||
|
||||
PreToken::PreGroup(_,_)
|
||||
| PreToken::Container(_)
|
||||
=> panic!()
|
||||
};
|
||||
|
||||
return t;
|
||||
|
||||
if let PreToken::PreWord(l, s) = &t {
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_some() {
|
||||
t = PreToken::PreOperator(*l, s.clone());
|
||||
}
|
||||
}
|
||||
|
||||
g.push_back(t);
|
||||
}
|
||||
|
||||
/// Turns a string into Tokens. First stage of parsing.
|
||||
|
@ -36,27 +52,11 @@ pub(in crate::parser) fn tokenize(input: &String) -> VecDeque<PreToken> {
|
|||
// The minus sign can be both a Negative and an Operator.
|
||||
// Needs special treatment.
|
||||
'-' => {
|
||||
if t.is_some() { g.push_back(update_line_location(t.unwrap(), i)); }
|
||||
match g.back().as_ref() {
|
||||
// If previous token was any of the following,
|
||||
// this is the "minus" operator
|
||||
Some(PreToken::PreNumber(_, _)) |
|
||||
Some(PreToken::PreGroupEnd(_)) |
|
||||
Some(PreToken::PreWord(_, _)) => {
|
||||
t = Some(PreToken::PreOperator(
|
||||
LineLocation{pos: i, len: 1},
|
||||
String::from("-")
|
||||
));
|
||||
},
|
||||
|
||||
// Otherwise, this is a negative sign.
|
||||
_ => {
|
||||
t = Some(PreToken::PreOperator(
|
||||
LineLocation{pos: i, len: 1},
|
||||
String::from("neg")
|
||||
));
|
||||
}
|
||||
};
|
||||
push_token(&mut g, t, i);
|
||||
t = Some(PreToken::PreOperator(
|
||||
LineLocation{pos: i, len: 1},
|
||||
String::from("-")
|
||||
));
|
||||
},
|
||||
|
||||
// Number
|
||||
|
@ -72,7 +72,7 @@ pub(in crate::parser) fn tokenize(input: &String) -> VecDeque<PreToken> {
|
|||
// If we're not building a number, finalize
|
||||
// previous token and start one.
|
||||
_ => {
|
||||
if t.is_some() { g.push_back(update_line_location(t.unwrap(), i)); }
|
||||
push_token(&mut g, t, i);
|
||||
t = Some(PreToken::PreNumber(LineLocation{pos: i, len: 0}, String::from(c)));
|
||||
}
|
||||
};
|
||||
|
@ -85,7 +85,7 @@ pub(in crate::parser) fn tokenize(input: &String) -> VecDeque<PreToken> {
|
|||
match &mut t {
|
||||
Some(PreToken::PreOperator(_, val)) => { val.push(c); },
|
||||
_ => {
|
||||
if t.is_some() { g.push_back(update_line_location(t.unwrap(), i)); }
|
||||
push_token(&mut g, t, i);
|
||||
t = Some(PreToken::PreOperator(LineLocation{pos: i, len: 0}, String::from(c)));
|
||||
}
|
||||
};
|
||||
|
@ -93,20 +93,18 @@ pub(in crate::parser) fn tokenize(input: &String) -> VecDeque<PreToken> {
|
|||
|
||||
// Group
|
||||
'(' => {
|
||||
if t.is_some() { g.push_back(update_line_location(t.unwrap(), i)); }
|
||||
push_token(&mut g, t, i);
|
||||
t = Some(PreToken::PreGroupStart(LineLocation{pos: i, len: 0}));
|
||||
},
|
||||
')' => {
|
||||
if t.is_some() { g.push_back(update_line_location(t.unwrap(), i)); }
|
||||
push_token(&mut g, t, i);
|
||||
t = Some(PreToken::PreGroupEnd(LineLocation{pos: i, len: 0}));
|
||||
},
|
||||
|
||||
// Space. Basic seperator.
|
||||
' ' => {
|
||||
if t.is_some() {
|
||||
g.push_back(update_line_location(t.unwrap(), i));
|
||||
t = None;
|
||||
}
|
||||
push_token(&mut g, t, i);
|
||||
t = None;
|
||||
}
|
||||
|
||||
// Word
|
||||
|
@ -115,7 +113,7 @@ pub(in crate::parser) fn tokenize(input: &String) -> VecDeque<PreToken> {
|
|||
Some(PreToken::PreWord(_, val)) => { val.push(c); },
|
||||
|
||||
_ => {
|
||||
if t.is_some() { g.push_back(update_line_location(t.unwrap(), i)); }
|
||||
push_token(&mut g, t, i);
|
||||
t = Some(PreToken::PreWord(LineLocation{pos: i, len: 0}, String::from(c)));
|
||||
}
|
||||
};
|
||||
|
@ -123,7 +121,7 @@ pub(in crate::parser) fn tokenize(input: &String) -> VecDeque<PreToken> {
|
|||
};
|
||||
}
|
||||
|
||||
if t.is_some() { g.push_back(update_line_location(t.unwrap(), input.chars().count())); }
|
||||
push_token(&mut g, t, input.chars().count());
|
||||
|
||||
return g;
|
||||
}
|
|
@ -3,17 +3,14 @@ use std::collections::VecDeque;
|
|||
|
||||
use crate::parser::PreToken;
|
||||
use crate::parser::ParserError;
|
||||
use crate::parser::LineLocation;
|
||||
|
||||
use crate::tokens::Token;
|
||||
use crate::tokens::Operator;
|
||||
use crate::tokens::LineLocation;
|
||||
|
||||
|
||||
|
||||
fn treeify_binary(
|
||||
i: usize,
|
||||
g_inner: &mut VecDeque<PreToken>,
|
||||
left_associative: bool
|
||||
g_inner: &mut VecDeque<PreToken>
|
||||
) -> Result<(), (LineLocation, ParserError)> {
|
||||
|
||||
let this: &PreToken = &g_inner[i];
|
||||
|
@ -27,45 +24,44 @@ fn treeify_binary(
|
|||
return Err((*l, ParserError::Syntax));
|
||||
}
|
||||
|
||||
let next: &PreToken;
|
||||
if left_associative {
|
||||
next = {
|
||||
if i < g_inner.len()-1 {
|
||||
&g_inner[i+1]
|
||||
} else {
|
||||
let l = match this {
|
||||
PreToken::PreOperator(l, _) => l,
|
||||
_ => panic!()
|
||||
};
|
||||
return Err((*l, ParserError::Syntax));
|
||||
}
|
||||
};
|
||||
} else {
|
||||
next = {
|
||||
if i > 0 {
|
||||
&g_inner[i-1]
|
||||
} else {
|
||||
let l = match this {
|
||||
PreToken::PreOperator(l, _) => l,
|
||||
_ => panic!()
|
||||
};
|
||||
return Err((*l, ParserError::Syntax));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let left = {
|
||||
if i > 0 {
|
||||
&g_inner[i-1]
|
||||
} else {
|
||||
let l = match this {
|
||||
PreToken::PreOperator(l, _) => l,
|
||||
_ => panic!()
|
||||
};
|
||||
return Err((*l, ParserError::Syntax));
|
||||
}
|
||||
};
|
||||
|
||||
let right = {
|
||||
if i < g_inner.len()-1 {
|
||||
&g_inner[i+1]
|
||||
} else {
|
||||
let l = match this {
|
||||
PreToken::PreOperator(l, _) => l,
|
||||
_ => panic!()
|
||||
};
|
||||
return Err((*l, ParserError::Syntax));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
if let PreToken::PreOperator(l, s) = next {
|
||||
|
||||
|
||||
if let PreToken::PreOperator(l, s) = left {
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||
let o = o.unwrap();
|
||||
|
||||
if {
|
||||
(!o.is_binary()) &&
|
||||
!(o.is_left_associative() && left_associative)
|
||||
o.is_left_associative()
|
||||
} {
|
||||
// Only right-associative unary operators can follow a binary operator
|
||||
return Ok(());
|
||||
} else {
|
||||
let tl = *this.get_line_location();
|
||||
|
@ -74,59 +70,79 @@ fn treeify_binary(
|
|||
ParserError::Syntax
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// Precedence of this operator
|
||||
let this_val = {
|
||||
let PreToken::PreOperator(l, s) = this else {panic!()};
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||
o.unwrap() as isize
|
||||
};
|
||||
}
|
||||
|
||||
// Precedence of the operators contesting our arguments
|
||||
let left_val = if i > 1 {
|
||||
let PreToken::PreOperator(l, s) = &g_inner[i-2] else {panic!()};
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||
Some(o.unwrap() as isize)
|
||||
} else { None };
|
||||
|
||||
let right_val = if i < g_inner.len()-2 {
|
||||
let PreToken::PreOperator(l, s) = &g_inner[i+2] else {panic!()};
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||
Some(o.unwrap() as isize)
|
||||
} else { None };
|
||||
if let PreToken::PreOperator(l, s) = right {
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||
let o = o.unwrap();
|
||||
|
||||
if {
|
||||
(left_val.is_none() || this_val >= left_val.unwrap()) &&
|
||||
(right_val.is_none() || this_val >= right_val.unwrap())
|
||||
(!o.is_binary()) &&
|
||||
!o.is_left_associative()
|
||||
} {
|
||||
// This operator has higher precedence, it takes both arguments
|
||||
let left_pre = g_inner.remove(i-1).unwrap();
|
||||
let this_pre = g_inner.remove(i-1).unwrap();
|
||||
let right_pre = g_inner.remove(i-1).unwrap();
|
||||
let left: Token; let right: Token;
|
||||
if let PreToken::PreGroup(_, _) = right_pre { right = treeify(right_pre)?; } else {right = right_pre.to_token()?;}
|
||||
if let PreToken::PreGroup(_, _) = left_pre { left = treeify(left_pre)?; } else {left = left_pre.to_token()?;}
|
||||
|
||||
let (l, o) = {
|
||||
let PreToken::PreOperator(l, s) = this_pre else {panic!()};
|
||||
let o = Operator::from_string(&s);
|
||||
if o.is_none() { panic!() }
|
||||
(l, o.unwrap())
|
||||
};
|
||||
|
||||
let mut new_token_args: VecDeque<Token> = VecDeque::with_capacity(2);
|
||||
new_token_args.push_back(left);
|
||||
new_token_args.push_back(right);
|
||||
|
||||
g_inner.insert(i-1, PreToken::Container(o.into_token(l, new_token_args)));
|
||||
|
||||
return Ok(());
|
||||
} else {
|
||||
return Ok(());
|
||||
let tl = *this.get_line_location();
|
||||
return Err((
|
||||
LineLocation{pos: tl.pos, len: l.pos - tl.pos + l.len},
|
||||
ParserError::Syntax
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Precedence of this operator
|
||||
let this_val = {
|
||||
let PreToken::PreOperator(l, s) = this else {panic!()};
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||
o.unwrap() as isize
|
||||
};
|
||||
|
||||
// Precedence of the operators contesting our arguments
|
||||
let left_val = if i > 1 {
|
||||
let PreToken::PreOperator(l, s) = &g_inner[i-2] else {panic!()};
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||
Some(o.unwrap() as isize)
|
||||
} else { None };
|
||||
|
||||
let right_val = if i < g_inner.len()-2 {
|
||||
let PreToken::PreOperator(l, s) = &g_inner[i+2] else {panic!()};
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||
Some(o.unwrap() as isize)
|
||||
} else { None };
|
||||
|
||||
if {
|
||||
(left_val.is_none() || this_val >= left_val.unwrap()) &&
|
||||
(right_val.is_none() || this_val >= right_val.unwrap())
|
||||
} {
|
||||
// This operator has higher precedence, it takes both arguments
|
||||
let left_pre = g_inner.remove(i-1).unwrap();
|
||||
let this_pre = g_inner.remove(i-1).unwrap();
|
||||
let right_pre = g_inner.remove(i-1).unwrap();
|
||||
let left: Token; let right: Token;
|
||||
if let PreToken::PreGroup(_, _) = right_pre { right = treeify(right_pre)?; } else {right = right_pre.to_token()?;}
|
||||
if let PreToken::PreGroup(_, _) = left_pre { left = treeify(left_pre)?; } else {left = left_pre.to_token()?;}
|
||||
|
||||
let o = {
|
||||
let PreToken::PreOperator(_, s) = this_pre else {panic!()};
|
||||
let o = Operator::from_string(&s);
|
||||
if o.is_none() { panic!() }
|
||||
o.unwrap()
|
||||
};
|
||||
|
||||
let mut new_token_args: VecDeque<Token> = VecDeque::with_capacity(2);
|
||||
new_token_args.push_back(left);
|
||||
new_token_args.push_back(right);
|
||||
|
||||
g_inner.insert(i-1, PreToken::Container(o.into_token(new_token_args)));
|
||||
|
||||
return Ok(());
|
||||
} else {
|
||||
return Ok(());
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -174,14 +190,7 @@ fn treeify_unary(
|
|||
}
|
||||
|
||||
if prev.is_some() {
|
||||
if let PreToken::PreOperator(l, s) = prev.unwrap() {
|
||||
let o = Operator::from_string(s);
|
||||
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||
let o = o.unwrap();
|
||||
|
||||
if o.is_left_associative() && left_associative {
|
||||
return Err((*l, ParserError::Syntax));
|
||||
}
|
||||
if let PreToken::PreOperator(_,_) = prev.unwrap() {
|
||||
} else {
|
||||
return Err((
|
||||
*this.get_line_location(),
|
||||
|
@ -190,8 +199,6 @@ fn treeify_unary(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if let PreToken::PreOperator(l, _) = next {
|
||||
let tl = *this.get_line_location();
|
||||
return Err((
|
||||
|
@ -236,20 +243,20 @@ fn treeify_unary(
|
|||
}
|
||||
if let PreToken::PreGroup(_, _) = next_pre { next = treeify(next_pre)?; } else { next = next_pre.to_token()? }
|
||||
|
||||
let (l, o) = {
|
||||
let PreToken::PreOperator(l, s) = this_pre else {panic!()};
|
||||
let o = {
|
||||
let PreToken::PreOperator(_, s) = this_pre else {panic!()};
|
||||
let o = Operator::from_string(&s);
|
||||
if o.is_none() { panic!() }
|
||||
(l, o.unwrap())
|
||||
o.unwrap()
|
||||
};
|
||||
|
||||
let mut new_token_args: VecDeque<Token> = VecDeque::with_capacity(3);
|
||||
new_token_args.push_back(next);
|
||||
|
||||
if left_associative {
|
||||
g_inner.insert(i-1, PreToken::Container(o.into_token(l, new_token_args)));
|
||||
g_inner.insert(i-1, PreToken::Container(o.into_token(new_token_args)));
|
||||
} else {
|
||||
g_inner.insert(i, PreToken::Container(o.into_token(l, new_token_args)));
|
||||
g_inner.insert(i, PreToken::Container(o.into_token(new_token_args)));
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
|
@ -300,7 +307,7 @@ pub(in crate::parser) fn treeify(
|
|||
if left_associative {
|
||||
if this_op.is_left_associative() {
|
||||
if this_op.is_binary() {
|
||||
treeify_binary(i, g_inner, left_associative)?;
|
||||
treeify_binary(i, g_inner)?;
|
||||
} else {
|
||||
treeify_unary(i, g_inner, left_associative)?;
|
||||
}
|
||||
|
@ -309,7 +316,7 @@ pub(in crate::parser) fn treeify(
|
|||
} else {
|
||||
if !this_op.is_left_associative() {
|
||||
if this_op.is_binary() {
|
||||
treeify_binary(i, g_inner, left_associative)?;
|
||||
treeify_binary(i, g_inner)?;
|
||||
} else {
|
||||
treeify_unary(i, g_inner, left_associative)?;
|
||||
}
|
||||
|
|
118
src/tokens.rs
118
src/tokens.rs
|
@ -1,26 +1,15 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
|
||||
/// Specifies the location of a token in an input string.
|
||||
/// Used to locate ParserErrors.
|
||||
#[derive(Debug)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct LineLocation {
|
||||
pub pos: usize,
|
||||
pub len: usize
|
||||
}
|
||||
|
||||
/// Tokens represent logical objects in an expession.
|
||||
///
|
||||
/// Tokens starting with `Pre*` are intermediate tokens, and
|
||||
/// will never show up in a fully-parsed expression tree.
|
||||
#[derive(Debug)]
|
||||
pub enum Token {
|
||||
Number(LineLocation, f64),
|
||||
Constant(LineLocation, f64, String),
|
||||
Number(f64),
|
||||
Constant(f64, String),
|
||||
|
||||
Operator(
|
||||
LineLocation,
|
||||
Operator,
|
||||
VecDeque<Token>
|
||||
),
|
||||
|
@ -30,27 +19,17 @@ impl Token {
|
|||
#[inline(always)]
|
||||
pub fn get_args(&mut self) -> Option<&mut VecDeque<Token>> {
|
||||
match self {
|
||||
Token::Operator(_, _, ref mut a) => Some(a),
|
||||
Token::Operator(_, ref mut a) => Some(a),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_line_location(&self) -> &LineLocation {
|
||||
match self {
|
||||
Token::Number(l, _)
|
||||
| Token::Operator(l, _, _)
|
||||
| Token::Constant(l, _, _)
|
||||
=> l,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn eval(&self) -> Token {
|
||||
match self {
|
||||
Token::Number(l,v) => { Token::Number(*l, *v) },
|
||||
Token::Constant(l,v,_) => { Token::Number(*l, *v) },
|
||||
Token::Operator(_,o,v) => { o.apply(v) }
|
||||
Token::Number(v) => { Token::Number(*v) },
|
||||
Token::Constant(v,_) => { Token::Number(*v) },
|
||||
Token::Operator(o,v) => { o.apply(v) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,8 +37,8 @@ impl Token {
|
|||
#[inline(always)]
|
||||
pub fn as_number(&self) -> Token {
|
||||
match self {
|
||||
Token::Number(l,v) => { Token::Number(*l, *v) },
|
||||
Token::Constant(l,v,_) => { Token::Number(*l, *v) },
|
||||
Token::Number(v) => { Token::Number(*v) },
|
||||
Token::Constant(v,_) => { Token::Number(*v) },
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +58,7 @@ pub enum Operator {
|
|||
Modulo, // Mod invoked with %
|
||||
Negative,
|
||||
Power,
|
||||
Sqrt,
|
||||
Factorial,
|
||||
|
||||
// Not accessible from prompt
|
||||
|
@ -99,6 +79,7 @@ impl Operator {
|
|||
"mod" => {Some( Operator::ModuloLong )},
|
||||
"^"|"**" => {Some( Operator::Power )},
|
||||
"!" => {Some( Operator::Factorial )},
|
||||
"sqrt"|"rt"|"√" => {Some( Operator::Sqrt )},
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +89,7 @@ impl Operator {
|
|||
match self {
|
||||
Operator::Negative
|
||||
| Operator::Factorial
|
||||
| Operator::Sqrt
|
||||
=> false,
|
||||
_ => true
|
||||
}
|
||||
|
@ -117,6 +99,7 @@ impl Operator {
|
|||
pub fn is_left_associative(&self) -> bool {
|
||||
match self {
|
||||
Operator::Negative
|
||||
| Operator::Sqrt
|
||||
=> false,
|
||||
_ => true
|
||||
}
|
||||
|
@ -124,16 +107,16 @@ impl Operator {
|
|||
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_token(self, l: LineLocation, mut args: VecDeque<Token>) -> Token {
|
||||
pub fn into_token(self, mut args: VecDeque<Token>) -> Token {
|
||||
match self {
|
||||
Operator::Subtract => {
|
||||
if args.len() != 2 { panic!() }
|
||||
let a = args.pop_front().unwrap();
|
||||
let b = args.pop_front().unwrap();
|
||||
let b = Token::Operator(l, Operator::Negative, VecDeque::from(vec!(b)));
|
||||
let b = Token::Operator(Operator::Negative, VecDeque::from(vec!(b)));
|
||||
|
||||
Token::Operator(
|
||||
l, Operator::Add,
|
||||
Operator::Add,
|
||||
VecDeque::from(vec!(a,b))
|
||||
)
|
||||
},
|
||||
|
@ -142,19 +125,29 @@ impl Operator {
|
|||
if args.len() != 2 { panic!() }
|
||||
let a = args.pop_front().unwrap();
|
||||
let b = args.pop_front().unwrap();
|
||||
let b = Token::Operator(l, Operator::Flip, VecDeque::from(vec!(b)));
|
||||
let b = Token::Operator(Operator::Flip, VecDeque::from(vec!(b)));
|
||||
|
||||
Token::Operator(
|
||||
l, Operator::Multiply,
|
||||
Operator::Multiply,
|
||||
VecDeque::from(vec!(a,b))
|
||||
)
|
||||
},
|
||||
|
||||
Operator::Sqrt => {
|
||||
if args.len() != 1 { panic!() }
|
||||
let a = args.pop_front().unwrap();
|
||||
|
||||
Token::Operator(
|
||||
Operator::Power,
|
||||
VecDeque::from(vec!(a, Token::Number(0.5)))
|
||||
)
|
||||
},
|
||||
|
||||
Operator::ImplicitMultiply
|
||||
=> { Token::Operator(l, Operator::Multiply, args) },
|
||||
=> { Token::Operator(Operator::Multiply, args) },
|
||||
|
||||
Operator::ModuloLong
|
||||
=> { Token::Operator(l, Operator::Modulo, args) },
|
||||
=> { Token::Operator(Operator::Modulo, args) },
|
||||
|
||||
Operator::Factorial
|
||||
| Operator::Negative
|
||||
|
@ -163,7 +156,7 @@ impl Operator {
|
|||
| Operator::Multiply
|
||||
| Operator::Modulo
|
||||
| Operator::Power
|
||||
=> { Token::Operator(l, self, args) },
|
||||
=> { Token::Operator(self, args) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +165,7 @@ impl Operator{
|
|||
pub fn apply(&self, args: &VecDeque<Token>) -> Token {
|
||||
match self {
|
||||
Operator::ImplicitMultiply |
|
||||
Operator::Sqrt |
|
||||
Operator::ModuloLong |
|
||||
Operator::Divide |
|
||||
Operator::Subtract => { panic!() }
|
||||
|
@ -180,8 +174,8 @@ impl Operator{
|
|||
if args.len() != 1 {panic!()};
|
||||
let args = args[0].as_number();
|
||||
|
||||
if let Token::Number(l, v) = args {
|
||||
Token::Number(l, -v)
|
||||
if let Token::Number(v) = args {
|
||||
Token::Number(-v)
|
||||
} else { panic!(); }
|
||||
},
|
||||
|
||||
|
@ -189,51 +183,35 @@ impl Operator{
|
|||
if args.len() != 1 {panic!()};
|
||||
let args = args[0].as_number();
|
||||
|
||||
if let Token::Number(l, v) = args {
|
||||
Token::Number(l, 1f64/v)
|
||||
if let Token::Number(v) = args {
|
||||
Token::Number(1f64/v)
|
||||
} else { panic!(); }
|
||||
},
|
||||
|
||||
Operator::Add => {
|
||||
let mut sum: f64 = 0f64;
|
||||
let mut new_pos: usize = 0;
|
||||
let mut new_len: usize = 0;
|
||||
for i in args.iter() {
|
||||
let j = i.as_number();
|
||||
if let Token::Number(l, v) = j {
|
||||
if new_pos == 0 {new_pos = l.pos};
|
||||
new_len = new_len + l.len;
|
||||
if let Token::Number(v) = j {
|
||||
sum += v;
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
Token::Number(
|
||||
LineLocation { pos: new_pos, len: new_len },
|
||||
sum
|
||||
)
|
||||
Token::Number(sum)
|
||||
},
|
||||
|
||||
Operator::Multiply => {
|
||||
let mut prod: f64 = 1f64;
|
||||
let mut new_pos: usize = 0;
|
||||
let mut new_len: usize = 0;
|
||||
for i in args.iter() {
|
||||
let j = i.as_number();
|
||||
if let Token::Number(l, v) = j {
|
||||
if new_pos == 0 {new_pos = l.pos};
|
||||
new_len = new_len + l.len;
|
||||
if let Token::Number(v) = j {
|
||||
prod *= v;
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
Token::Number(
|
||||
LineLocation { pos: new_pos, len: new_len },
|
||||
prod
|
||||
)
|
||||
Token::Number(prod)
|
||||
},
|
||||
|
||||
Operator::Modulo => {
|
||||
|
@ -241,12 +219,9 @@ impl Operator{
|
|||
let a = args[0].as_number();
|
||||
let b = args[1].as_number();
|
||||
|
||||
if let Token::Number(la, va) = a {
|
||||
if let Token::Number(lb, vb) = b {
|
||||
Token::Number(
|
||||
LineLocation { pos: la.pos, len: lb.pos - la.pos + lb.len },
|
||||
va%vb
|
||||
)
|
||||
if let Token::Number(va) = a {
|
||||
if let Token::Number(vb) = b {
|
||||
Token::Number(va%vb)
|
||||
} else { panic!(); }
|
||||
} else { panic!(); }
|
||||
},
|
||||
|
@ -256,12 +231,9 @@ impl Operator{
|
|||
let a = args[0].as_number();
|
||||
let b = args[1].as_number();
|
||||
|
||||
if let Token::Number(la, va) = a {
|
||||
if let Token::Number(lb, vb) = b {
|
||||
Token::Number(
|
||||
LineLocation { pos: la.pos, len: lb.pos - la.pos + lb.len },
|
||||
va.powf(vb)
|
||||
)
|
||||
if let Token::Number(va) = a {
|
||||
if let Token::Number(vb) = b {
|
||||
Token::Number(va.powf(vb))
|
||||
} else { panic!(); }
|
||||
} else { panic!(); }
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue