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