From 74b29455e5d511871cd46bdefd68726d076f2073 Mon Sep 17 00:00:00 2001 From: Book-reader Date: Fri, 5 Sep 2025 23:58:06 +1200 Subject: [PATCH] Constants work and *finally* fix the off-by-one in lexing --- asklyphe-frontend/src/math.rs | 40 +++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/asklyphe-frontend/src/math.rs b/asklyphe-frontend/src/math.rs index 125061f..683530c 100644 --- a/asklyphe-frontend/src/math.rs +++ b/asklyphe-frontend/src/math.rs @@ -120,6 +120,8 @@ impl Atom { Atom::Const(c) => match c { Const::Pi => 3.141592653589793238462643383279, Const::E => 2.718281828459045235360287471352, + Const::Inf => f64::INFINITY, + Const::Nan => f64::NAN, } } } @@ -167,8 +169,23 @@ impl Func { enum Const { Pi, E, + Inf, + Nan, } + +impl Const { + fn names() -> &'static [(Const, &'static [&'static str])] { + &[ + (Const::Pi, &["pi", "PI", "π"]), + (Const::E, &["e", "euler"]), + (Const::Inf, &["inf", "infinity", "∞"]), + (Const::Nan, &["nan", "NaN"]) + ] + } +} + + #[derive(Debug, Copy, Clone, PartialEq)] enum ParseErr { Eof, @@ -224,12 +241,22 @@ impl Lexer<'_> { let len = self.data_ptr.chars().count(); 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() }; + let n_len = name.chars().count(); + if self.data_ptr.starts_with(name) && (len == n_len || !self.data_ptr.chars().nth(n_len).unwrap().is_alphabetic()) { + self.next_by = name.chars().count(); return Ok(Token::Op(Op::Func(*f))); } } } + for (f, names) in Const::names() { + for name in *names { + let n_len = name.chars().count(); + if self.data_ptr.starts_with(name) && (len == n_len || !self.data_ptr.chars().nth(n_len).unwrap().is_alphabetic()) { + self.next_by = name.chars().count(); + return Ok(Token::Atom(Atom::Const(*f))); + } + } + } debug!("got invalid char '{}'", val); Err(ParseErr::Invalid) } @@ -299,8 +326,13 @@ impl Parser<'_> { Token::Op(op) => match op { Op::LParen => { let val = self.parse_expr(0.0); - assert_eq!(self.lex.next(), Ok(Token::Op(Op::RParen))); - val + if self.lex.next() != Ok(Token::Op(Op::RParen)) { + debug!("Unclosed parens"); + Err(ParseErr::Invalid) + } + else { + val + } }, // Op::Func(f) => Ok(Expr::Node(Op::Func(f), vec![self.parse_expr(op.get_lbp())?])), _ => match op.bp_prefix() {