Added square root, fixed many parser bugs

pull/2/head
Mark 2023-03-28 10:46:29 -07:00
parent 6db5137b56
commit 71d9aaa039
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
7 changed files with 277 additions and 239 deletions

View File

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

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,29 +52,13 @@ 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(_, _)) => {
push_token(&mut g, t, i);
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
// Commas act just like dots.
',' | '.' | '0'..='9' => {
@ -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,21 +93,19 @@ 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));
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,21 +24,8 @@ 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 = {
let left = {
if i > 0 {
&g_inner[i-1]
} else {
@ -52,20 +36,32 @@ fn treeify_binary(
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,7 +70,28 @@ fn treeify_binary(
ParserError::Syntax
));
}
}
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 {
(!o.is_binary()) &&
!o.is_left_associative()
} {
return Ok(());
} else {
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!()};
@ -110,24 +127,23 @@ fn treeify_binary(
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 = {
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(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)));
g_inner.insert(i-1, PreToken::Container(o.into_token(new_token_args)));
return Ok(());
} else {
return Ok(());
};
};
}
fn treeify_unary(
@ -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)?;
}

View File

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