Constants work and *finally* fix the off-by-one in lexing

This commit is contained in:
Book-reader 2025-09-05 23:58:06 +12:00
parent 47477732ba
commit 74b29455e5

View file

@ -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)));
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() {