forked from asklyphe-public/asklyphe
Compare commits
2 commits
9c9172d4c9
...
328ec0bfdc
| Author | SHA1 | Date | |
|---|---|---|---|
| 328ec0bfdc | |||
| 199bce4f90 |
1 changed files with 89 additions and 81 deletions
|
|
@ -30,65 +30,6 @@ enum Token {
|
|||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum Op {
|
||||
BinOp(BinOp),
|
||||
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 {
|
||||
fn get_lbp(&self) -> f64 {
|
||||
match self {
|
||||
Op::BinOp(op) => match op {
|
||||
BinOp::LParen => 0.0,
|
||||
BinOp::RParen => 0.0,
|
||||
BinOp::Add => 1.0,
|
||||
BinOp::Subtract => 1.0,
|
||||
BinOp::Multiply => 2.0,
|
||||
BinOp::Divide => 2.0,
|
||||
BinOp::Exponent => 3.1,
|
||||
},
|
||||
Op::Func(_) => 0.0, // TODO: decide if this is a good LBP
|
||||
}
|
||||
}
|
||||
|
||||
fn get_rbp(&self) -> f64 {
|
||||
match self {
|
||||
Op::BinOp(op) => match op {
|
||||
BinOp::LParen => 0.0,
|
||||
BinOp::RParen => 0.0,
|
||||
BinOp::Add => 1.1,
|
||||
BinOp::Subtract => 1.1,
|
||||
BinOp::Multiply => 2.1,
|
||||
BinOp::Divide => 2.1,
|
||||
BinOp::Exponent => 3.0,
|
||||
},
|
||||
Op::Func(_) => 4.0, // TODO: decide if this is a good RBP
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn apply_to(&self, args: &Vec<Expr>) -> f64 {
|
||||
match (self) {
|
||||
Op::BinOp(op) => match op {
|
||||
BinOp::LParen => args[0].eval(),
|
||||
BinOp::RParen => args[0].eval(),
|
||||
BinOp::Add => args[0].eval() + args[1].eval(),
|
||||
BinOp::Subtract => args[0].eval() - args[1].eval(),
|
||||
BinOp::Multiply => args[0].eval() * args[1].eval(),
|
||||
BinOp::Divide => args[0].eval() / args[1].eval(),
|
||||
BinOp::Exponent => args[0].eval().powf(args[1].eval()),
|
||||
},
|
||||
Op::Func(f) => match f {
|
||||
Func::Sine => args[0].eval().sin(),
|
||||
Func::ArcSine => args[0].eval().asin(),
|
||||
Func::SquareRoot => args[0].eval().sqrt(),
|
||||
_ => todo!("{:?}", f),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum BinOp {
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
|
|
@ -96,6 +37,71 @@ enum BinOp {
|
|||
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
|
||||
}
|
||||
|
||||
impl Op {
|
||||
fn bp_infix(&self) -> Option<(f64, f64)> {
|
||||
match self {
|
||||
// Op::LParen => Some(0.0),
|
||||
// Op::RParen => Some(0.0),
|
||||
Op::Add => Some((1.0, 1.1)),
|
||||
Op::Subtract => Some((1.0, 1.1)),
|
||||
Op::Multiply => Some((2.0, 2.1)),
|
||||
Op::Divide => Some((2.0, 2.1)),
|
||||
Op::Exponent => Some((3.1, 3.0)),
|
||||
_ => None,
|
||||
// Op::Func(_) => 0.0, // TODO: decide if this is a good LBP
|
||||
}
|
||||
}
|
||||
|
||||
fn bp_prefix(&self) -> Option<f64> {
|
||||
match self {
|
||||
Op::Func(_) => Some(0.1),
|
||||
Op::Subtract => Some(5.0),
|
||||
Op::Add => Some(5.0),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_to(&self, args: &Vec<Expr>) -> f64 {
|
||||
match args.len() {
|
||||
1 => match self {
|
||||
Op::Subtract => Some(0.0 - args[0].eval()),
|
||||
Op::Add => Some(args[0].eval().abs()),
|
||||
Op::Func(f) => match f {
|
||||
Func::Sine => Some(args[0].eval().sin()),
|
||||
Func::Cosine => Some(args[0].eval().cos()),
|
||||
Func::Tangent => Some(args[0].eval().tan()),
|
||||
Func::ArcSine => Some(args[0].eval().asin()),
|
||||
Func::ArcCosine => Some(args[0].eval().acos()),
|
||||
Func::ArcTangent => Some(args[0].eval().atan()),
|
||||
Func::Log2 => Some(args[0].eval().log2()),
|
||||
Func::Log10 => Some(args[0].eval().log10()),
|
||||
// Func::LogN => Some(),
|
||||
Func::Square => Some(args[0].eval().powf(2.0)),
|
||||
Func::SquareRoot => Some(args[0].eval().sqrt()),
|
||||
_ => todo!("{:?}", self)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
2 => match self {
|
||||
Op::LParen => Some(args[0].eval()),
|
||||
Op::RParen => Some(args[0].eval()),
|
||||
Op::Add => Some(args[0].eval() + args[1].eval()),
|
||||
Op::Subtract => 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::Exponent => Some(args[0].eval().powf(args[1].eval())),
|
||||
_ => None,
|
||||
}
|
||||
_ => None,
|
||||
}.unwrap_or_else(|| {
|
||||
error!("ERROR when evaluating maths expression, got invalid number of args ({}) for {:?}", args.len(), self);
|
||||
// None
|
||||
f64::NAN
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
|
@ -172,13 +178,13 @@ impl Lexer<'_> {
|
|||
// TODO: make more efficient
|
||||
self.data_ptr = &self.data[self.idx..];
|
||||
match val {
|
||||
'+' => Ok(Token::Op(Op::BinOp(BinOp::Add))),
|
||||
'-' => Ok(Token::Op(Op::BinOp(BinOp::Subtract))),
|
||||
'×' | '*' => Ok(Token::Op(Op::BinOp(BinOp::Multiply))),
|
||||
'÷' | '/' => Ok(Token::Op(Op::BinOp(BinOp::Divide))),
|
||||
'^' => Ok(Token::Op(Op::BinOp(BinOp::Exponent))),
|
||||
'(' => Ok(Token::Op(Op::BinOp(BinOp::LParen))),
|
||||
')' => Ok(Token::Op(Op::BinOp(BinOp::RParen))),
|
||||
'+' => Ok(Token::Op(Op::Add)),
|
||||
'-' => Ok(Token::Op(Op::Subtract)),
|
||||
'×' | '*' => Ok(Token::Op(Op::Multiply)),
|
||||
'÷' | '/' => Ok(Token::Op(Op::Divide)),
|
||||
'^' => Ok(Token::Op(Op::Exponent)),
|
||||
'(' => Ok(Token::Op(Op::LParen)),
|
||||
')' => Ok(Token::Op(Op::RParen)),
|
||||
_ if val.is_whitespace() => self._next(),
|
||||
// TODO: maybe parse '-' as part of number so I can do '1 + -1' and similar
|
||||
_ if val.is_digit(10) => {
|
||||
|
|
@ -293,9 +299,12 @@ impl Parser<'_> {
|
|||
Ok(val) => match val {
|
||||
Token::Atom(val) => Ok(Expr::Atom(val)),
|
||||
Token::Op(op) => match op {
|
||||
Op::BinOp(BinOp::LParen) => 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),
|
||||
Op::LParen => self.parse_expr(0.0),
|
||||
// Op::Func(f) => Ok(Expr::Node(Op::Func(f), vec![self.parse_expr(op.get_lbp())?])),
|
||||
_ => match op.bp_prefix() {
|
||||
Some(bp) => Ok(Expr::Node(op, vec![self.parse_expr(bp)?])),
|
||||
None => {debug!("Got unexpected {:?} as prefix", op); Err(ParseErr::Invalid)}
|
||||
}
|
||||
},
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
|
|
@ -307,22 +316,21 @@ impl Parser<'_> {
|
|||
Err(e) => { debug!("In expr got err {:?}", e); Err(e) },
|
||||
Ok(tok) => match tok {
|
||||
Token::Op(op) => match op {
|
||||
Op::BinOp(op) => match op {
|
||||
BinOp::RParen => break,
|
||||
_ => Ok(Op::BinOp(op)),
|
||||
},
|
||||
Op::Func(f) => {
|
||||
lhs = Expr::Node(Op::Func(f), vec![self.parse_expr(Op::Func(f).get_lbp())?]);
|
||||
continue;
|
||||
},
|
||||
Op::RParen => break,
|
||||
_ => Ok(op),
|
||||
}
|
||||
v => { debug!("Got unexpected token {:?}", v); Err(ParseErr::Invalid) },
|
||||
}
|
||||
}.map_err(|err| { debug!("Unexpected error inside expr at {:?}", err); err })?;
|
||||
if (op.get_lbp() < min_bp) { break; }
|
||||
self.lex.next();
|
||||
let rhs: Expr = self.parse_expr(op.get_rbp())?;
|
||||
lhs = Expr::Node(op, vec![lhs, rhs]);
|
||||
if let Some((lbp, rbp)) = op.bp_infix() {
|
||||
if (lbp < min_bp) { break; }
|
||||
self.lex.next();
|
||||
let rhs: Expr = self.parse_expr(rbp)?;
|
||||
lhs = Expr::Node(op, vec![lhs, rhs]);
|
||||
} else {
|
||||
debug!("Got unexpected non-infix operator in expression: {:?}", op);
|
||||
return Err(ParseErr::Invalid);
|
||||
}
|
||||
}
|
||||
Ok(lhs)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue