This commit is contained in:
Book-reader 2025-09-05 21:14:04 +12:00
parent 9c9172d4c9
commit 199bce4f90

View file

@ -30,53 +30,61 @@ enum Token {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
enum Op { enum Op {
BinOp(BinOp), Add,
Subtract,
Multiply,
Divide,
Exponent,
LParen,
RParen,
Func(Func), // A function is an Op that takes whatever the next thing is and binds it, either the next number or whatever is in parens Func(Func), // A function is an Op that takes whatever the next thing is and binds it, either the next number or whatever is in parens
} }
impl Op { impl Op {
fn get_lbp(&self) -> f64 { fn get_lbp(&self) -> f64 {
match self { match self {
Op::BinOp(op) => match op { Op::LParen => 0.0,
BinOp::LParen => 0.0, Op::RParen => 0.0,
BinOp::RParen => 0.0, Op::Add => 1.0,
BinOp::Add => 1.0, Op::Subtract => 1.0,
BinOp::Subtract => 1.0, Op::Multiply => 2.0,
BinOp::Multiply => 2.0, Op::Divide => 2.0,
BinOp::Divide => 2.0, Op::Exponent => 3.1,
BinOp::Exponent => 3.1,
},
Op::Func(_) => 0.0, // TODO: decide if this is a good LBP Op::Func(_) => 0.0, // TODO: decide if this is a good LBP
} }
} }
fn get_rbp(&self) -> f64 { fn get_rbp(&self) -> f64 {
match self { match self {
Op::BinOp(op) => match op { Op::LParen => 0.0,
BinOp::LParen => 0.0, Op::RParen => 0.0,
BinOp::RParen => 0.0, Op::Add => 1.1,
BinOp::Add => 1.1, Op::Subtract => 1.1,
BinOp::Subtract => 1.1, Op::Multiply => 2.1,
BinOp::Multiply => 2.1, Op::Divide => 2.1,
BinOp::Divide => 2.1, Op::Exponent => 3.0,
BinOp::Exponent => 3.0,
},
Op::Func(_) => 4.0, // TODO: decide if this is a good RBP Op::Func(_) => 4.0, // TODO: decide if this is a good RBP
} }
} }
// Prefix binding power
// fn get_pbp(&self) -> Option<f64> {
// match self {
// Op::BinOp(op) => match op {
// BinOp::
// }
// }
// }
fn apply_to(&self, args: &Vec<Expr>) -> f64 { fn apply_to(&self, args: &Vec<Expr>) -> f64 {
match (self) { match (self) {
Op::BinOp(op) => match op { Op::LParen => args[0].eval(),
BinOp::LParen => args[0].eval(), Op::RParen => args[0].eval(),
BinOp::RParen => args[0].eval(), Op::Add => args[0].eval() + args[1].eval(),
BinOp::Add => args[0].eval() + args[1].eval(), Op::Subtract => args[0].eval() - args[1].eval(),
BinOp::Subtract => args[0].eval() - args[1].eval(), Op::Multiply => args[0].eval() * args[1].eval(),
BinOp::Multiply => args[0].eval() * args[1].eval(), Op::Divide => args[0].eval() / args[1].eval(),
BinOp::Divide => args[0].eval() / args[1].eval(), Op::Exponent => args[0].eval().powf(args[1].eval()),
BinOp::Exponent => args[0].eval().powf(args[1].eval()),
},
Op::Func(f) => match f { Op::Func(f) => match f {
Func::Sine => args[0].eval().sin(), Func::Sine => args[0].eval().sin(),
Func::ArcSine => args[0].eval().asin(), Func::ArcSine => args[0].eval().asin(),
@ -87,17 +95,6 @@ impl Op {
} }
} }
#[derive(Debug, Copy, Clone)]
enum BinOp {
Add,
Subtract,
Multiply,
Divide,
Exponent,
LParen,
RParen,
}
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
enum Atom { enum Atom {
Number(f64), // TODO: use the high precision floats library instead Number(f64), // TODO: use the high precision floats library instead
@ -172,13 +169,13 @@ impl Lexer<'_> {
// TODO: make more efficient // TODO: make more efficient
self.data_ptr = &self.data[self.idx..]; self.data_ptr = &self.data[self.idx..];
match val { match val {
'+' => Ok(Token::Op(Op::BinOp(BinOp::Add))), '+' => Ok(Token::Op(Op::Add)),
'-' => Ok(Token::Op(Op::BinOp(BinOp::Subtract))), '-' => Ok(Token::Op(Op::Subtract)),
'×' | '*' => Ok(Token::Op(Op::BinOp(BinOp::Multiply))), '×' | '*' => Ok(Token::Op(Op::Multiply)),
'÷' | '/' => Ok(Token::Op(Op::BinOp(BinOp::Divide))), '÷' | '/' => Ok(Token::Op(Op::Divide)),
'^' => Ok(Token::Op(Op::BinOp(BinOp::Exponent))), '^' => Ok(Token::Op(Op::Exponent)),
'(' => Ok(Token::Op(Op::BinOp(BinOp::LParen))), '(' => Ok(Token::Op(Op::LParen)),
')' => Ok(Token::Op(Op::BinOp(BinOp::RParen))), ')' => Ok(Token::Op(Op::RParen)),
_ if val.is_whitespace() => self._next(), _ if val.is_whitespace() => self._next(),
// TODO: maybe parse '-' as part of number so I can do '1 + -1' and similar // TODO: maybe parse '-' as part of number so I can do '1 + -1' and similar
_ if val.is_digit(10) => { _ if val.is_digit(10) => {
@ -293,7 +290,7 @@ 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::BinOp(BinOp::LParen) => self.parse_expr(op.get_lbp()), Op::LParen => self.parse_expr(op.get_lbp()),
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())?])),
_ => Err(ParseErr::Invalid), _ => Err(ParseErr::Invalid),
}, },
@ -307,14 +304,12 @@ impl Parser<'_> {
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::BinOp(op) => match op { Op::RParen => break,
BinOp::RParen => break,
_ => Ok(Op::BinOp(op)),
},
Op::Func(f) => { Op::Func(f) => {
lhs = Expr::Node(Op::Func(f), vec![self.parse_expr(Op::Func(f).get_lbp())?]); lhs = Expr::Node(Op::Func(f), vec![self.parse_expr(Op::Func(f).get_lbp())?]);
continue; continue;
}, },
_ => Ok(op),
} }
v => { debug!("Got unexpected token {:?}", v); Err(ParseErr::Invalid) }, v => { debug!("Got unexpected token {:?}", v); Err(ParseErr::Invalid) },
} }