finish up lexing & do some parsing improvements (functions now require parens for multiple args :(, I'll see if I can change that later)

This commit is contained in:
Book-reader 2025-09-05 23:32:21 +12:00
parent cbf35e9746
commit 47477732ba

View file

@ -20,7 +20,7 @@ pub fn calculate(query: &str) -> Option<Calculation> {
} }
// TODO: put into own crate with dependency astro-float = "0.9.2" so I can use more than f64 // TODO: put into own crate with dependency astro-float = "0.9.2" so I can use more than f64
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
enum Token { enum Token {
Op(Op), Op(Op),
Atom(Atom), Atom(Atom),
@ -28,7 +28,7 @@ enum Token {
Func(Func),*/ Func(Func),*/
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
enum Op { enum Op {
Add, Add,
Subtract, Subtract,
@ -57,7 +57,7 @@ impl Op {
fn bp_prefix(&self) -> Option<f64> { fn bp_prefix(&self) -> Option<f64> {
match self { match self {
Op::Func(_) => Some(0.1), Op::Func(_) => Some(6.0),
Op::Subtract => Some(5.0), Op::Subtract => Some(5.0),
Op::Add => Some(5.0), Op::Add => Some(5.0),
_ => None, _ => None,
@ -78,10 +78,12 @@ impl Op {
Func::ArcTangent => Some(args[0].eval().atan()), Func::ArcTangent => Some(args[0].eval().atan()),
Func::Log2 => Some(args[0].eval().log2()), Func::Log2 => Some(args[0].eval().log2()),
Func::Log10 => Some(args[0].eval().log10()), Func::Log10 => Some(args[0].eval().log10()),
Func::LogN => Some(args[0].eval().ln()),
Func::Square => Some(args[0].eval().powf(2.0)), Func::Square => Some(args[0].eval().powf(2.0)),
Func::SquareRoot => Some(args[0].eval().sqrt()), Func::SquareRoot => Some(args[0].eval().sqrt()),
Func::LogN => None, Func::Abs => Some(args[0].eval().abs()),
_ => todo!("{:?}", self) Func::Log => None,
// _ => todo!("{:?}", self)
} }
_ => None, _ => None,
} }
@ -93,7 +95,7 @@ impl Op {
Op::Multiply => Some(args[0].eval() * args[1].eval()), Op::Multiply => Some(args[0].eval() * args[1].eval()),
Op::Divide => Some(args[0].eval() / args[1].eval()), Op::Divide => Some(args[0].eval() / args[1].eval()),
Op::Exponent => Some(args[0].eval().powf(args[1].eval())), Op::Exponent => Some(args[0].eval().powf(args[1].eval())),
Op::Func(Func::LogN) => Some(args[0].eval().log(args[1].eval())), Op::Func(Func::Log) => Some(args[0].eval().log(args[1].eval())),
_ => None, _ => None,
} }
_ => None, _ => None,
@ -105,7 +107,7 @@ impl Op {
} }
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
enum Atom { enum Atom {
Number(f64), // TODO: use the high precision floats library instead Number(f64), // TODO: use the high precision floats library instead
Const(Const), Const(Const),
@ -123,7 +125,7 @@ impl Atom {
} }
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
enum Func { enum Func {
Sine, Sine,
Cosine, Cosine,
@ -135,17 +137,39 @@ enum Func {
Log2, Log2,
Log10, Log10,
LogN, LogN,
Log,
Square, Square,
SquareRoot, SquareRoot,
Abs,
} }
#[derive(Debug, Copy, Clone)] impl Func {
fn names() -> &'static [(Func, &'static [&'static str])] {
&[
(Func::Sine, &["sin", "sine"]),
(Func::Cosine, &["cos", "cosine"]),
(Func::Tangent, &["tan", "tangent"]),
(Func::ArcSine, &["asin", "asine", "arcsin", "arcsine"]),
(Func::ArcCosine, &["acos", "acosine", "arccos", "arccosine"]),
(Func::ArcTangent, &["atan", "atangent", "arctan", "arctangent"]),
(Func::Log2, &["log2"]),
(Func::Log10, &["log10"]),
(Func::LogN, &["ln", "logn"]),
(Func::Log, &["log"]),
(Func::Square, &["square", "squared"]),
(Func::SquareRoot, &["sqrt", "squareroot", ""]),
(Func::Abs, &["abs", "absolute"]),
]
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
enum Const { enum Const {
Pi, Pi,
E, E,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq)]
enum ParseErr { enum ParseErr {
Eof, Eof,
Invalid, Invalid,
@ -189,7 +213,7 @@ impl Lexer<'_> {
_ if val.is_digit(10) => { _ if val.is_digit(10) => {
let mut len: usize = 0; let mut len: usize = 0;
self.data_ptr.chars().take_while(|c| c.is_digit(10) || *c == '.').for_each(|_| len += 1); self.data_ptr.chars().take_while(|c| c.is_digit(10) || *c == '.').for_each(|_| len += 1);
self.next_by += len - 1; self.next_by = len;
match self.data_ptr[..len].parse() { match self.data_ptr[..len].parse() {
Ok(val) => Ok(Token::Atom(Atom::Number(val))), Ok(val) => Ok(Token::Atom(Atom::Number(val))),
@ -197,46 +221,15 @@ impl Lexer<'_> {
} }
}, },
_ => { _ => {
/* match (&self.data[self.idx - 1..]) { let len = self.data_ptr.chars().count();
s if s.starts_with("" for (f, names) in Func::names() {
for name in *names {
if self.data_ptr.starts_with(name) {
self.next_by = if self.data_ptr.len() > name.len() { name.chars().count() + 1} else { name.chars().count() };
return Ok(Token::Op(Op::Func(*f)));
}
}
} }
let mut l: usize;
l = matches(&self.data[self.idx - 1..], "sin");
if l != 0 {
self.idx += l;
return Ok(Token::Op(Op::Func(Func::Sine)));
}
l = matches(&self.data[self.idx - 1..], "cos");
if l != 0 {
self.idx += l;
return Ok(Token::Op(Op::Func(Func::Cosine)));
}
l = matches(&self.data[self.idx - 1..], "tan");
if l != 0 {
self.idx += l;
return Ok(Token::Op(Op::Func(Func::Tangent)));
}
l = matches(&self.data[self.idx - 1..], "arcsin");
if l != 0 {
self.idx += l;
return Ok(Token::Op(Op::Func(Func::ArcSine)));
}
l = matches(&self.data[self.idx - 1..], "arccos");
if l != 0 {
self.idx += l;
return Ok(Token::Op(Op::Func(Func::ArcCosine)));
}
l = matches(&self.data[self.idx - 1..], "arctan");
if l != 0 {
self.idx += l;
return Ok(Token::Op(Op::Func(Func::ArcTangent)));
}
l = matches(&self.data[self.idx - 1..], "sqrt");
if l != 0 {
self.idx += l;
return Ok(Token::Op(Op::Func(Func::SquareRoot)));
}
*/
debug!("got invalid char '{}'", val); debug!("got invalid char '{}'", val);
Err(ParseErr::Invalid) Err(ParseErr::Invalid)
} }
@ -304,7 +297,11 @@ impl Parser<'_> {
Ok(val) => match val { Ok(val) => match val {
Token::Atom(val) => Ok(Expr::Atom(val)), Token::Atom(val) => Ok(Expr::Atom(val)),
Token::Op(op) => match op { Token::Op(op) => match op {
Op::LParen => self.parse_expr(0.0), Op::LParen => {
let val = self.parse_expr(0.0);
assert_eq!(self.lex.next(), Ok(Token::Op(Op::RParen)));
val
},
// Op::Func(f) => Ok(Expr::Node(Op::Func(f), vec![self.parse_expr(op.get_lbp())?])), // Op::Func(f) => Ok(Expr::Node(Op::Func(f), vec![self.parse_expr(op.get_lbp())?])),
_ => match op.bp_prefix() { _ => match op.bp_prefix() {
Some(bp) => Ok(Expr::Node(op, vec![self.parse_expr(bp)?])), Some(bp) => Ok(Expr::Node(op, vec![self.parse_expr(bp)?])),
@ -314,19 +311,24 @@ impl Parser<'_> {
}, },
Err(err) => Err(err), Err(err) => Err(err),
}.map_err(|err| { debug!("Unexpected error at start of expr: {:?}", err); err })?; }.map_err(|err| { debug!("Unexpected error at start of expr: {:?}", err); err })?;
debug!("lhs of expression is {:?}", lhs); debug!("lhs of expression is {:?}, min_bp is {}", lhs, min_bp);
loop { loop {
debug!("loop start");
let op: Op = match self.lex.peek() { let op: Op = match self.lex.peek() {
Err(ParseErr::Eof) => break, Err(ParseErr::Eof) => break,
Err(e) => { debug!("In expr got err {:?}", e); Err(e) }, Err(e) => { debug!("In expr got err {:?}", e); Err(e) },
Ok(tok) => match tok { Ok(tok) => match tok {
Token::Op(op) => match op { Token::Op(op) => match op {
Op::RParen => break, Op::RParen => {
debug!("got RParen");
break;
},
_ => Ok(op), _ => Ok(op),
} }
v => { debug!("Got unexpected token {:?}", v); Err(ParseErr::Invalid) }, v => { debug!("Got unexpected token {:?}", v); Err(ParseErr::Invalid) },
} }
}.map_err(|err| { debug!("Unexpected error inside expr at {:?}", err); err })?; }.map_err(|err| { debug!("Unexpected error inside expr at {:?}", err); err })?;
debug!("op is {:?}", op);
if let Some((lbp, rbp)) = op.bp_infix() { if let Some((lbp, rbp)) = op.bp_infix() {
if (lbp < min_bp) { break; } if (lbp < min_bp) { break; }
self.lex.next(); self.lex.next();
@ -337,6 +339,7 @@ impl Parser<'_> {
return Err(ParseErr::Invalid); return Err(ParseErr::Invalid);
} }
} }
debug!("Returning expr {:?}", lhs);
Ok(lhs) Ok(lhs)
} }
} }