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