forked from asklyphe-public/asklyphe
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:
parent
cbf35e9746
commit
47477732ba
1 changed files with 56 additions and 53 deletions
|
@ -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
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
enum Token {
|
||||
Op(Op),
|
||||
Atom(Atom),
|
||||
|
@ -28,7 +28,7 @@ enum Token {
|
|||
Func(Func),*/
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
enum Op {
|
||||
Add,
|
||||
Subtract,
|
||||
|
@ -57,7 +57,7 @@ impl Op {
|
|||
|
||||
fn bp_prefix(&self) -> Option<f64> {
|
||||
match self {
|
||||
Op::Func(_) => Some(0.1),
|
||||
Op::Func(_) => Some(6.0),
|
||||
Op::Subtract => Some(5.0),
|
||||
Op::Add => Some(5.0),
|
||||
_ => None,
|
||||
|
@ -78,10 +78,12 @@ impl Op {
|
|||
Func::ArcTangent => Some(args[0].eval().atan()),
|
||||
Func::Log2 => Some(args[0].eval().log2()),
|
||||
Func::Log10 => Some(args[0].eval().log10()),
|
||||
Func::LogN => Some(args[0].eval().ln()),
|
||||
Func::Square => Some(args[0].eval().powf(2.0)),
|
||||
Func::SquareRoot => Some(args[0].eval().sqrt()),
|
||||
Func::LogN => None,
|
||||
_ => todo!("{:?}", self)
|
||||
Func::Abs => Some(args[0].eval().abs()),
|
||||
Func::Log => None,
|
||||
// _ => todo!("{:?}", self)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
@ -93,7 +95,7 @@ impl Op {
|
|||
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())),
|
||||
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,
|
||||
|
@ -105,7 +107,7 @@ impl Op {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
enum Atom {
|
||||
Number(f64), // TODO: use the high precision floats library instead
|
||||
Const(Const),
|
||||
|
@ -123,7 +125,7 @@ impl Atom {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
enum Func {
|
||||
Sine,
|
||||
Cosine,
|
||||
|
@ -135,17 +137,39 @@ enum Func {
|
|||
Log2,
|
||||
Log10,
|
||||
LogN,
|
||||
Log,
|
||||
Square,
|
||||
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 {
|
||||
Pi,
|
||||
E,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
enum ParseErr {
|
||||
Eof,
|
||||
Invalid,
|
||||
|
@ -189,7 +213,7 @@ impl Lexer<'_> {
|
|||
_ if val.is_digit(10) => {
|
||||
let mut len: usize = 0;
|
||||
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() {
|
||||
Ok(val) => Ok(Token::Atom(Atom::Number(val))),
|
||||
|
@ -197,46 +221,15 @@ impl Lexer<'_> {
|
|||
}
|
||||
},
|
||||
_ => {
|
||||
/* match (&self.data[self.idx - 1..]) {
|
||||
s if s.starts_with(""
|
||||
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() };
|
||||
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);
|
||||
Err(ParseErr::Invalid)
|
||||
}
|
||||
|
@ -304,7 +297,11 @@ impl Parser<'_> {
|
|||
Ok(val) => match val {
|
||||
Token::Atom(val) => Ok(Expr::Atom(val)),
|
||||
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())?])),
|
||||
_ => match op.bp_prefix() {
|
||||
Some(bp) => Ok(Expr::Node(op, vec![self.parse_expr(bp)?])),
|
||||
|
@ -314,19 +311,24 @@ impl Parser<'_> {
|
|||
},
|
||||
Err(err) => 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 {
|
||||
debug!("loop start");
|
||||
let op: Op = match self.lex.peek() {
|
||||
Err(ParseErr::Eof) => break,
|
||||
Err(e) => { debug!("In expr got err {:?}", e); Err(e) },
|
||||
Ok(tok) => match tok {
|
||||
Token::Op(op) => match op {
|
||||
Op::RParen => break,
|
||||
Op::RParen => {
|
||||
debug!("got RParen");
|
||||
break;
|
||||
},
|
||||
_ => Ok(op),
|
||||
}
|
||||
v => { debug!("Got unexpected token {:?}", v); Err(ParseErr::Invalid) },
|
||||
}
|
||||
}.map_err(|err| { debug!("Unexpected error inside expr at {:?}", err); err })?;
|
||||
debug!("op is {:?}", op);
|
||||
if let Some((lbp, rbp)) = op.bp_infix() {
|
||||
if (lbp < min_bp) { break; }
|
||||
self.lex.next();
|
||||
|
@ -337,6 +339,7 @@ impl Parser<'_> {
|
|||
return Err(ParseErr::Invalid);
|
||||
}
|
||||
}
|
||||
debug!("Returning expr {:?}", lhs);
|
||||
Ok(lhs)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue