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 {
|
match h {
|
||||||
Token::Operator(_,_,_)
|
Token::Operator(_,_)
|
||||||
=> {
|
=> {
|
||||||
coords.push(0);
|
coords.push(0);
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
},
|
},
|
||||||
|
|
||||||
Token::Constant(_,_,_) |
|
Token::Constant(_,_) |
|
||||||
Token::Number(_,_) => {
|
Token::Number(_) => {
|
||||||
let l = coords.pop().unwrap();
|
let l = coords.pop().unwrap();
|
||||||
coords.push(l + 1);
|
coords.push(l + 1);
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use crate::parser::PreToken;
|
use crate::parser::PreToken;
|
||||||
use crate::tokens::LineLocation;
|
use crate::parser::LineLocation;
|
||||||
|
|
||||||
|
|
||||||
pub(in crate::parser) fn find_subs(
|
pub(in crate::parser) fn find_subs(
|
||||||
|
@ -64,7 +64,10 @@ pub(in crate::parser) fn find_subs(
|
||||||
"chi" => {Some("χ")},
|
"chi" => {Some("χ")},
|
||||||
"psi" => {Some("ψ")},
|
"psi" => {Some("ψ")},
|
||||||
"omega" => {Some("ω")},
|
"omega" => {Some("ω")},
|
||||||
|
|
||||||
|
// Operators
|
||||||
"sqrt" => {Some("√")},
|
"sqrt" => {Some("√")},
|
||||||
|
"rt" => {Some("√")},
|
||||||
|
|
||||||
_ => {None}
|
_ => {None}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,28 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use crate::tokens::LineLocation;
|
|
||||||
use crate::tokens::Operator;
|
|
||||||
use crate::parser::PreToken;
|
use crate::parser::PreToken;
|
||||||
|
use crate::parser::LineLocation;
|
||||||
use crate::parser::ParserError;
|
use crate::parser::ParserError;
|
||||||
|
|
||||||
|
use crate::tokens::Operator;
|
||||||
|
|
||||||
// Inserts implicit operators
|
// Inserts implicit operators
|
||||||
fn lookback(
|
fn lookback(
|
||||||
g: &mut VecDeque<PreToken>
|
g: &mut VecDeque<PreToken>
|
||||||
) -> Result<(), (LineLocation, ParserError)> {
|
) -> 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 b: PreToken = g.pop_back().unwrap();
|
||||||
let a: PreToken = g.pop_back().unwrap();
|
let a: PreToken = g.pop_back().unwrap();
|
||||||
|
|
||||||
|
@ -42,10 +54,58 @@ fn lookback(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following are fine
|
(PreToken::PreOperator(_, sa), PreToken::PreOperator(l,sb))
|
||||||
(PreToken::PreOperator(_,_), _) |
|
=> {
|
||||||
(_, PreToken::PreOperator(_,_))
|
if sb == "-" && {
|
||||||
=> { g.push_back(a); g.push_back(b); },
|
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.
|
// This shouldn't ever happen.
|
||||||
(PreToken::PreGroupStart(_), _)
|
(PreToken::PreGroupStart(_), _)
|
||||||
|
@ -102,16 +162,6 @@ pub(in crate::parser) fn groupify(
|
||||||
lookback(v_now)?;
|
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);
|
v_now.push_back(t);
|
||||||
lookback(v_now)?;
|
lookback(v_now)?;
|
||||||
|
|
|
@ -12,9 +12,17 @@ use crate::parser::groupify::groupify;
|
||||||
use crate::parser::treeify::treeify;
|
use crate::parser::treeify::treeify;
|
||||||
use crate::parser::find_subs::find_subs;
|
use crate::parser::find_subs::find_subs;
|
||||||
|
|
||||||
use crate::tokens::LineLocation;
|
|
||||||
use crate::tokens::Token;
|
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)]
|
#[derive(Debug)]
|
||||||
enum PreToken {
|
enum PreToken {
|
||||||
PreNumber(LineLocation, String),
|
PreNumber(LineLocation, String),
|
||||||
|
@ -67,14 +75,14 @@ impl PreToken {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(_) => return Err((l, ParserError::BadNumber))
|
Err(_) => return Err((l, ParserError::BadNumber))
|
||||||
};
|
};
|
||||||
return Ok(Token::Number(l, n));
|
return Ok(Token::Number(n));
|
||||||
},
|
},
|
||||||
PreToken::PreWord(l, s) => {
|
PreToken::PreWord(l, s) => {
|
||||||
return Ok(match &s[..] {
|
return Ok(match &s[..] {
|
||||||
// Mathematical constants
|
// Mathematical constants
|
||||||
"π"|"pi" => { Token::Constant(l, 3.141592653, String::from("pi")) },
|
"π"|"pi" => { Token::Constant(3.141592653, String::from("pi")) },
|
||||||
"e" => { Token::Constant(l, 2.71828, String::from("e")) },
|
"e" => { Token::Constant(2.71828, String::from("e")) },
|
||||||
"phi"|"φ" => { Token::Constant(l, 1.61803, String::from("phi")) },
|
"phi"|"φ" => { Token::Constant(1.61803, String::from("phi")) },
|
||||||
_ => { return Err((l, ParserError::Undefined(s))); }
|
_ => { return Err((l, ParserError::Undefined(s))); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,44 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use crate::parser::PreToken;
|
use crate::parser::PreToken;
|
||||||
use crate::tokens::LineLocation;
|
use crate::parser::LineLocation;
|
||||||
|
|
||||||
/// Updates the length of a Token's LineLocation.
|
use crate::tokens::Operator;
|
||||||
/// Run whenever a token is finished.
|
|
||||||
|
// Called whenever a token is finished.
|
||||||
#[inline(always)]
|
#[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 {
|
match t {
|
||||||
PreToken::PreGroupStart(ref mut l) |
|
PreToken::PreGroupStart(ref mut l)
|
||||||
PreToken::PreGroupEnd(ref mut l) |
|
| PreToken::PreGroupEnd(ref mut l)
|
||||||
PreToken::PreOperator(ref mut l, _) |
|
| PreToken::PreOperator(ref mut l, _)
|
||||||
PreToken::PreNumber(ref mut l, _) |
|
| PreToken::PreNumber(ref mut l, _)
|
||||||
PreToken::PreWord(ref mut l, _)
|
| PreToken::PreWord(ref mut l, _)
|
||||||
=> {
|
=> {
|
||||||
*l = LineLocation{
|
*l = LineLocation{
|
||||||
pos: l.pos,
|
pos: l.pos,
|
||||||
len: stop_i - 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.
|
/// 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.
|
// The minus sign can be both a Negative and an Operator.
|
||||||
// Needs special treatment.
|
// Needs special treatment.
|
||||||
'-' => {
|
'-' => {
|
||||||
if t.is_some() { g.push_back(update_line_location(t.unwrap(), i)); }
|
push_token(&mut g, t, i);
|
||||||
match g.back().as_ref() {
|
t = Some(PreToken::PreOperator(
|
||||||
// If previous token was any of the following,
|
LineLocation{pos: i, len: 1},
|
||||||
// this is the "minus" operator
|
String::from("-")
|
||||||
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")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Number
|
// Number
|
||||||
|
@ -72,7 +72,7 @@ pub(in crate::parser) fn tokenize(input: &String) -> VecDeque<PreToken> {
|
||||||
// If we're not building a number, finalize
|
// If we're not building a number, finalize
|
||||||
// previous token and start one.
|
// 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)));
|
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 {
|
match &mut t {
|
||||||
Some(PreToken::PreOperator(_, val)) => { val.push(c); },
|
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)));
|
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
|
// 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}));
|
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}));
|
t = Some(PreToken::PreGroupEnd(LineLocation{pos: i, len: 0}));
|
||||||
},
|
},
|
||||||
|
|
||||||
// Space. Basic seperator.
|
// Space. Basic seperator.
|
||||||
' ' => {
|
' ' => {
|
||||||
if t.is_some() {
|
push_token(&mut g, t, i);
|
||||||
g.push_back(update_line_location(t.unwrap(), i));
|
t = None;
|
||||||
t = None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Word
|
// Word
|
||||||
|
@ -115,7 +113,7 @@ pub(in crate::parser) fn tokenize(input: &String) -> VecDeque<PreToken> {
|
||||||
Some(PreToken::PreWord(_, val)) => { val.push(c); },
|
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)));
|
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;
|
return g;
|
||||||
}
|
}
|
|
@ -3,17 +3,14 @@ use std::collections::VecDeque;
|
||||||
|
|
||||||
use crate::parser::PreToken;
|
use crate::parser::PreToken;
|
||||||
use crate::parser::ParserError;
|
use crate::parser::ParserError;
|
||||||
|
use crate::parser::LineLocation;
|
||||||
|
|
||||||
use crate::tokens::Token;
|
use crate::tokens::Token;
|
||||||
use crate::tokens::Operator;
|
use crate::tokens::Operator;
|
||||||
use crate::tokens::LineLocation;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn treeify_binary(
|
fn treeify_binary(
|
||||||
i: usize,
|
i: usize,
|
||||||
g_inner: &mut VecDeque<PreToken>,
|
g_inner: &mut VecDeque<PreToken>
|
||||||
left_associative: bool
|
|
||||||
) -> Result<(), (LineLocation, ParserError)> {
|
) -> Result<(), (LineLocation, ParserError)> {
|
||||||
|
|
||||||
let this: &PreToken = &g_inner[i];
|
let this: &PreToken = &g_inner[i];
|
||||||
|
@ -27,45 +24,44 @@ fn treeify_binary(
|
||||||
return Err((*l, ParserError::Syntax));
|
return Err((*l, ParserError::Syntax));
|
||||||
}
|
}
|
||||||
|
|
||||||
let next: &PreToken;
|
|
||||||
if left_associative {
|
let left = {
|
||||||
next = {
|
if i > 0 {
|
||||||
if i < g_inner.len()-1 {
|
&g_inner[i-1]
|
||||||
&g_inner[i+1]
|
} else {
|
||||||
} else {
|
let l = match this {
|
||||||
let l = match this {
|
PreToken::PreOperator(l, _) => l,
|
||||||
PreToken::PreOperator(l, _) => l,
|
_ => panic!()
|
||||||
_ => panic!()
|
};
|
||||||
};
|
return Err((*l, ParserError::Syntax));
|
||||||
return Err((*l, ParserError::Syntax));
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
} else {
|
let right = {
|
||||||
next = {
|
if i < g_inner.len()-1 {
|
||||||
if i > 0 {
|
&g_inner[i+1]
|
||||||
&g_inner[i-1]
|
} else {
|
||||||
} else {
|
let l = match this {
|
||||||
let l = match this {
|
PreToken::PreOperator(l, _) => l,
|
||||||
PreToken::PreOperator(l, _) => l,
|
_ => panic!()
|
||||||
_ => panic!()
|
};
|
||||||
};
|
return Err((*l, ParserError::Syntax));
|
||||||
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);
|
let o = Operator::from_string(s);
|
||||||
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||||
let o = o.unwrap();
|
let o = o.unwrap();
|
||||||
|
|
||||||
if {
|
if {
|
||||||
(!o.is_binary()) &&
|
(!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(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
let tl = *this.get_line_location();
|
let tl = *this.get_line_location();
|
||||||
|
@ -74,59 +70,79 @@ fn treeify_binary(
|
||||||
ParserError::Syntax
|
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
|
if let PreToken::PreOperator(l, s) = right {
|
||||||
let left_val = if i > 1 {
|
let o = Operator::from_string(s);
|
||||||
let PreToken::PreOperator(l, s) = &g_inner[i-2] else {panic!()};
|
if o.is_none() { return Err((*l, ParserError::Syntax)); }
|
||||||
let o = Operator::from_string(s);
|
let o = o.unwrap();
|
||||||
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 {
|
if {
|
||||||
(left_val.is_none() || this_val >= left_val.unwrap()) &&
|
(!o.is_binary()) &&
|
||||||
(right_val.is_none() || this_val >= right_val.unwrap())
|
!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(());
|
return Ok(());
|
||||||
} else {
|
} 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 prev.is_some() {
|
||||||
if let PreToken::PreOperator(l, s) = prev.unwrap() {
|
if let PreToken::PreOperator(_,_) = 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));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return Err((
|
return Err((
|
||||||
*this.get_line_location(),
|
*this.get_line_location(),
|
||||||
|
@ -190,8 +199,6 @@ fn treeify_unary(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if let PreToken::PreOperator(l, _) = next {
|
if let PreToken::PreOperator(l, _) = next {
|
||||||
let tl = *this.get_line_location();
|
let tl = *this.get_line_location();
|
||||||
return Err((
|
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()? }
|
if let PreToken::PreGroup(_, _) = next_pre { next = treeify(next_pre)?; } else { next = next_pre.to_token()? }
|
||||||
|
|
||||||
let (l, o) = {
|
let o = {
|
||||||
let PreToken::PreOperator(l, s) = this_pre else {panic!()};
|
let PreToken::PreOperator(_, s) = this_pre else {panic!()};
|
||||||
let o = Operator::from_string(&s);
|
let o = Operator::from_string(&s);
|
||||||
if o.is_none() { panic!() }
|
if o.is_none() { panic!() }
|
||||||
(l, o.unwrap())
|
o.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut new_token_args: VecDeque<Token> = VecDeque::with_capacity(3);
|
let mut new_token_args: VecDeque<Token> = VecDeque::with_capacity(3);
|
||||||
new_token_args.push_back(next);
|
new_token_args.push_back(next);
|
||||||
|
|
||||||
if left_associative {
|
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 {
|
} 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(());
|
return Ok(());
|
||||||
|
@ -300,7 +307,7 @@ pub(in crate::parser) fn treeify(
|
||||||
if left_associative {
|
if left_associative {
|
||||||
if this_op.is_left_associative() {
|
if this_op.is_left_associative() {
|
||||||
if this_op.is_binary() {
|
if this_op.is_binary() {
|
||||||
treeify_binary(i, g_inner, left_associative)?;
|
treeify_binary(i, g_inner)?;
|
||||||
} else {
|
} else {
|
||||||
treeify_unary(i, g_inner, left_associative)?;
|
treeify_unary(i, g_inner, left_associative)?;
|
||||||
}
|
}
|
||||||
|
@ -309,7 +316,7 @@ pub(in crate::parser) fn treeify(
|
||||||
} else {
|
} else {
|
||||||
if !this_op.is_left_associative() {
|
if !this_op.is_left_associative() {
|
||||||
if this_op.is_binary() {
|
if this_op.is_binary() {
|
||||||
treeify_binary(i, g_inner, left_associative)?;
|
treeify_binary(i, g_inner)?;
|
||||||
} else {
|
} else {
|
||||||
treeify_unary(i, g_inner, left_associative)?;
|
treeify_unary(i, g_inner, left_associative)?;
|
||||||
}
|
}
|
||||||
|
|
118
src/tokens.rs
118
src/tokens.rs
|
@ -1,26 +1,15 @@
|
||||||
use std::collections::VecDeque;
|
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 represent logical objects in an expession.
|
||||||
///
|
///
|
||||||
/// 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.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
Number(LineLocation, f64),
|
Number(f64),
|
||||||
Constant(LineLocation, f64, String),
|
Constant(f64, String),
|
||||||
|
|
||||||
Operator(
|
Operator(
|
||||||
LineLocation,
|
|
||||||
Operator,
|
Operator,
|
||||||
VecDeque<Token>
|
VecDeque<Token>
|
||||||
),
|
),
|
||||||
|
@ -30,27 +19,17 @@ impl Token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn get_args(&mut self) -> Option<&mut VecDeque<Token>> {
|
pub fn get_args(&mut self) -> Option<&mut VecDeque<Token>> {
|
||||||
match self {
|
match self {
|
||||||
Token::Operator(_, _, ref mut a) => Some(a),
|
Token::Operator(_, ref mut a) => Some(a),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn get_line_location(&self) -> &LineLocation {
|
|
||||||
match self {
|
|
||||||
Token::Number(l, _)
|
|
||||||
| Token::Operator(l, _, _)
|
|
||||||
| Token::Constant(l, _, _)
|
|
||||||
=> l,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn eval(&self) -> Token {
|
pub fn eval(&self) -> Token {
|
||||||
match self {
|
match self {
|
||||||
Token::Number(l,v) => { Token::Number(*l, *v) },
|
Token::Number(v) => { Token::Number(*v) },
|
||||||
Token::Constant(l,v,_) => { Token::Number(*l, *v) },
|
Token::Constant(v,_) => { Token::Number(*v) },
|
||||||
Token::Operator(_,o,v) => { o.apply(v) }
|
Token::Operator(o,v) => { o.apply(v) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,8 +37,8 @@ impl Token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn as_number(&self) -> Token {
|
pub fn as_number(&self) -> Token {
|
||||||
match self {
|
match self {
|
||||||
Token::Number(l,v) => { Token::Number(*l, *v) },
|
Token::Number(v) => { Token::Number(*v) },
|
||||||
Token::Constant(l,v,_) => { Token::Number(*l, *v) },
|
Token::Constant(v,_) => { Token::Number(*v) },
|
||||||
_ => panic!()
|
_ => panic!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,6 +58,7 @@ pub enum Operator {
|
||||||
Modulo, // Mod invoked with %
|
Modulo, // Mod invoked with %
|
||||||
Negative,
|
Negative,
|
||||||
Power,
|
Power,
|
||||||
|
Sqrt,
|
||||||
Factorial,
|
Factorial,
|
||||||
|
|
||||||
// Not accessible from prompt
|
// Not accessible from prompt
|
||||||
|
@ -99,6 +79,7 @@ impl Operator {
|
||||||
"mod" => {Some( Operator::ModuloLong )},
|
"mod" => {Some( Operator::ModuloLong )},
|
||||||
"^"|"**" => {Some( Operator::Power )},
|
"^"|"**" => {Some( Operator::Power )},
|
||||||
"!" => {Some( Operator::Factorial )},
|
"!" => {Some( Operator::Factorial )},
|
||||||
|
"sqrt"|"rt"|"√" => {Some( Operator::Sqrt )},
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,6 +89,7 @@ impl Operator {
|
||||||
match self {
|
match self {
|
||||||
Operator::Negative
|
Operator::Negative
|
||||||
| Operator::Factorial
|
| Operator::Factorial
|
||||||
|
| Operator::Sqrt
|
||||||
=> false,
|
=> false,
|
||||||
_ => true
|
_ => true
|
||||||
}
|
}
|
||||||
|
@ -117,6 +99,7 @@ impl Operator {
|
||||||
pub fn is_left_associative(&self) -> bool {
|
pub fn is_left_associative(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Operator::Negative
|
Operator::Negative
|
||||||
|
| Operator::Sqrt
|
||||||
=> false,
|
=> false,
|
||||||
_ => true
|
_ => true
|
||||||
}
|
}
|
||||||
|
@ -124,16 +107,16 @@ impl Operator {
|
||||||
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[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 {
|
match self {
|
||||||
Operator::Subtract => {
|
Operator::Subtract => {
|
||||||
if args.len() != 2 { panic!() }
|
if args.len() != 2 { panic!() }
|
||||||
let a = args.pop_front().unwrap();
|
let a = args.pop_front().unwrap();
|
||||||
let b = 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(
|
Token::Operator(
|
||||||
l, Operator::Add,
|
Operator::Add,
|
||||||
VecDeque::from(vec!(a,b))
|
VecDeque::from(vec!(a,b))
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -142,19 +125,29 @@ impl Operator {
|
||||||
if args.len() != 2 { panic!() }
|
if args.len() != 2 { panic!() }
|
||||||
let a = args.pop_front().unwrap();
|
let a = args.pop_front().unwrap();
|
||||||
let b = 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(
|
Token::Operator(
|
||||||
l, Operator::Multiply,
|
Operator::Multiply,
|
||||||
VecDeque::from(vec!(a,b))
|
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
|
Operator::ImplicitMultiply
|
||||||
=> { Token::Operator(l, Operator::Multiply, args) },
|
=> { Token::Operator(Operator::Multiply, args) },
|
||||||
|
|
||||||
Operator::ModuloLong
|
Operator::ModuloLong
|
||||||
=> { Token::Operator(l, Operator::Modulo, args) },
|
=> { Token::Operator(Operator::Modulo, args) },
|
||||||
|
|
||||||
Operator::Factorial
|
Operator::Factorial
|
||||||
| Operator::Negative
|
| Operator::Negative
|
||||||
|
@ -163,7 +156,7 @@ impl Operator {
|
||||||
| Operator::Multiply
|
| Operator::Multiply
|
||||||
| Operator::Modulo
|
| Operator::Modulo
|
||||||
| Operator::Power
|
| 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 {
|
pub fn apply(&self, args: &VecDeque<Token>) -> Token {
|
||||||
match self {
|
match self {
|
||||||
Operator::ImplicitMultiply |
|
Operator::ImplicitMultiply |
|
||||||
|
Operator::Sqrt |
|
||||||
Operator::ModuloLong |
|
Operator::ModuloLong |
|
||||||
Operator::Divide |
|
Operator::Divide |
|
||||||
Operator::Subtract => { panic!() }
|
Operator::Subtract => { panic!() }
|
||||||
|
@ -180,8 +174,8 @@ impl Operator{
|
||||||
if args.len() != 1 {panic!()};
|
if args.len() != 1 {panic!()};
|
||||||
let args = args[0].as_number();
|
let args = args[0].as_number();
|
||||||
|
|
||||||
if let Token::Number(l, v) = args {
|
if let Token::Number(v) = args {
|
||||||
Token::Number(l, -v)
|
Token::Number(-v)
|
||||||
} else { panic!(); }
|
} else { panic!(); }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -189,51 +183,35 @@ impl Operator{
|
||||||
if args.len() != 1 {panic!()};
|
if args.len() != 1 {panic!()};
|
||||||
let args = args[0].as_number();
|
let args = args[0].as_number();
|
||||||
|
|
||||||
if let Token::Number(l, v) = args {
|
if let Token::Number(v) = args {
|
||||||
Token::Number(l, 1f64/v)
|
Token::Number(1f64/v)
|
||||||
} else { panic!(); }
|
} else { panic!(); }
|
||||||
},
|
},
|
||||||
|
|
||||||
Operator::Add => {
|
Operator::Add => {
|
||||||
let mut sum: f64 = 0f64;
|
let mut sum: f64 = 0f64;
|
||||||
let mut new_pos: usize = 0;
|
|
||||||
let mut new_len: usize = 0;
|
|
||||||
for i in args.iter() {
|
for i in args.iter() {
|
||||||
let j = i.as_number();
|
let j = i.as_number();
|
||||||
if let Token::Number(l, v) = j {
|
if let Token::Number(v) = j {
|
||||||
if new_pos == 0 {new_pos = l.pos};
|
|
||||||
new_len = new_len + l.len;
|
|
||||||
sum += v;
|
sum += v;
|
||||||
} else {
|
} else {
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Token::Number(sum)
|
||||||
Token::Number(
|
|
||||||
LineLocation { pos: new_pos, len: new_len },
|
|
||||||
sum
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Operator::Multiply => {
|
Operator::Multiply => {
|
||||||
let mut prod: f64 = 1f64;
|
let mut prod: f64 = 1f64;
|
||||||
let mut new_pos: usize = 0;
|
|
||||||
let mut new_len: usize = 0;
|
|
||||||
for i in args.iter() {
|
for i in args.iter() {
|
||||||
let j = i.as_number();
|
let j = i.as_number();
|
||||||
if let Token::Number(l, v) = j {
|
if let Token::Number(v) = j {
|
||||||
if new_pos == 0 {new_pos = l.pos};
|
|
||||||
new_len = new_len + l.len;
|
|
||||||
prod *= v;
|
prod *= v;
|
||||||
} else {
|
} else {
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Token::Number(prod)
|
||||||
Token::Number(
|
|
||||||
LineLocation { pos: new_pos, len: new_len },
|
|
||||||
prod
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Operator::Modulo => {
|
Operator::Modulo => {
|
||||||
|
@ -241,12 +219,9 @@ impl Operator{
|
||||||
let a = args[0].as_number();
|
let a = args[0].as_number();
|
||||||
let b = args[1].as_number();
|
let b = args[1].as_number();
|
||||||
|
|
||||||
if let Token::Number(la, va) = a {
|
if let Token::Number(va) = a {
|
||||||
if let Token::Number(lb, vb) = b {
|
if let Token::Number(vb) = b {
|
||||||
Token::Number(
|
Token::Number(va%vb)
|
||||||
LineLocation { pos: la.pos, len: lb.pos - la.pos + lb.len },
|
|
||||||
va%vb
|
|
||||||
)
|
|
||||||
} else { panic!(); }
|
} else { panic!(); }
|
||||||
} else { panic!(); }
|
} else { panic!(); }
|
||||||
},
|
},
|
||||||
|
@ -256,12 +231,9 @@ impl Operator{
|
||||||
let a = args[0].as_number();
|
let a = args[0].as_number();
|
||||||
let b = args[1].as_number();
|
let b = args[1].as_number();
|
||||||
|
|
||||||
if let Token::Number(la, va) = a {
|
if let Token::Number(va) = a {
|
||||||
if let Token::Number(lb, vb) = b {
|
if let Token::Number(vb) = b {
|
||||||
Token::Number(
|
Token::Number(va.powf(vb))
|
||||||
LineLocation { pos: la.pos, len: lb.pos - la.pos + lb.len },
|
|
||||||
va.powf(vb)
|
|
||||||
)
|
|
||||||
} else { panic!(); }
|
} else { panic!(); }
|
||||||
} else { panic!(); }
|
} else { panic!(); }
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue