Added square root, fixed many parser bugs

This commit is contained in:
2023-03-28 10:46:29 -07:00
parent 6db5137b56
commit 71d9aaa039
7 changed files with 277 additions and 239 deletions

View File

@ -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}
};

View File

@ -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)?;

View File

@ -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))); }
});
}

View File

@ -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;
}

View File

@ -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)?;
}