Parsing seems to work now!
This commit is contained in:
		
							parent
							
								
									c2f210c32c
								
							
						
					
					
						commit
						849393fbd1
					
				
					 1 changed files with 89 additions and 28 deletions
				
			
		| 
						 | 
					@ -17,7 +17,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)]
 | 
					#[derive(Debug, Copy, Clone)]
 | 
				
			||||||
enum Token {
 | 
					enum Token {
 | 
				
			||||||
	Op(Op),
 | 
						Op(Op),
 | 
				
			||||||
	Atom(Atom),
 | 
						Atom(Atom),
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,7 @@ enum Token {
 | 
				
			||||||
	Func(Func),*/
 | 
						Func(Func),*/
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Copy, Clone)]
 | 
				
			||||||
enum Op {
 | 
					enum Op {
 | 
				
			||||||
	BinOp(BinOp),
 | 
						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
 | 
						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
 | 
				
			||||||
| 
						 | 
					@ -33,15 +33,38 @@ enum Op {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Op {
 | 
					impl Op {
 | 
				
			||||||
	fn get_lbp(&self) -> f64 {
 | 
						fn get_lbp(&self) -> f64 {
 | 
				
			||||||
		todo!();
 | 
							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.0,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Op::Func(_) => 2.9, // TODO: decide if this is a good LBP
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn get_rbp(&self) -> f64 {
 | 
						fn get_rbp(&self) -> f64 {
 | 
				
			||||||
		todo!();
 | 
							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.1,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Op::Func(_) => 4.0, // TODO: decide if this is a good RBP
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Copy, Clone)]
 | 
				
			||||||
enum BinOp {
 | 
					enum BinOp {
 | 
				
			||||||
	Add,
 | 
						Add,
 | 
				
			||||||
	Subtract,
 | 
						Subtract,
 | 
				
			||||||
| 
						 | 
					@ -52,13 +75,13 @@ enum BinOp {
 | 
				
			||||||
	RParen,
 | 
						RParen,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Copy, Clone)]
 | 
				
			||||||
enum Atom {
 | 
					enum Atom {
 | 
				
			||||||
	Number(f64), // TODO: use the unlimited precision floats library instead
 | 
						Number(f64), // TODO: use the high precision floats library instead
 | 
				
			||||||
	Const(Const),
 | 
						Const(Const),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Copy, Clone)]
 | 
				
			||||||
enum Func {
 | 
					enum Func {
 | 
				
			||||||
	Sine,
 | 
						Sine,
 | 
				
			||||||
	Cosine,
 | 
						Cosine,
 | 
				
			||||||
| 
						 | 
					@ -74,13 +97,13 @@ enum Func {
 | 
				
			||||||
	SquareRoot,
 | 
						SquareRoot,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Copy, Clone)]
 | 
				
			||||||
enum Const {
 | 
					enum Const {
 | 
				
			||||||
	Pi,
 | 
						Pi,
 | 
				
			||||||
	E,
 | 
						E,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Copy, Clone)]
 | 
				
			||||||
enum ParseErr {
 | 
					enum ParseErr {
 | 
				
			||||||
	Eof,
 | 
						Eof,
 | 
				
			||||||
	Invalid,
 | 
						Invalid,
 | 
				
			||||||
| 
						 | 
					@ -92,14 +115,20 @@ struct Lexer<'a> {
 | 
				
			||||||
	data: &'a str,
 | 
						data: &'a str,
 | 
				
			||||||
	data_ptr: &'a str,
 | 
						data_ptr: &'a str,
 | 
				
			||||||
	idx: usize,
 | 
						idx: usize,
 | 
				
			||||||
 | 
						next_tok: Result<Token, ParseErr>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: refactor with iterator that returns Option(Token) where one token option is Eof (or a enum of Token(Token) and Eof, or just Option(Option(Token)))
 | 
					// TODO: refactor with iterator that returns Option(Token) where one token option is Eof (or a enum of Token(Token) and Eof, or just Option(Option(Token)))
 | 
				
			||||||
impl Lexer<'_> {
 | 
					impl Lexer<'_> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn new(data: &str) -> Lexer<'_> { Lexer {data, data_ptr: data, idx: 0} }
 | 
						fn new(data: &str) -> Lexer<'_> {
 | 
				
			||||||
 | 
							let mut n: Lexer = Lexer {data, data_ptr: data, idx: 0, next_tok: Err(ParseErr::Eof)};
 | 
				
			||||||
 | 
							n.next();
 | 
				
			||||||
 | 
							debug!("New finished!");
 | 
				
			||||||
 | 
							n
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	fn next(&mut self) -> Result<Token, ParseErr> {
 | 
						fn _next(&mut self) -> Result<Token, ParseErr> {
 | 
				
			||||||
		match self.data.chars().nth(self.idx) {
 | 
							match self.data.chars().nth(self.idx) {
 | 
				
			||||||
			Some(val) => {
 | 
								Some(val) => {
 | 
				
			||||||
				debug!("lexing char '{}' at idx {}", val, self.idx);
 | 
									debug!("lexing char '{}' at idx {}", val, self.idx);
 | 
				
			||||||
| 
						 | 
					@ -115,7 +144,7 @@ impl Lexer<'_> {
 | 
				
			||||||
					'^' => Ok(Token::Op(Op::BinOp(BinOp::Exponent))),
 | 
										'^' => Ok(Token::Op(Op::BinOp(BinOp::Exponent))),
 | 
				
			||||||
					'(' => Ok(Token::Op(Op::BinOp(BinOp::LParen))),
 | 
										'(' => Ok(Token::Op(Op::BinOp(BinOp::LParen))),
 | 
				
			||||||
					')' => Ok(Token::Op(Op::BinOp(BinOp::RParen))),
 | 
										')' => Ok(Token::Op(Op::BinOp(BinOp::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) => {
 | 
				
			||||||
						let start = self.idx - 1;
 | 
											let start = self.idx - 1;
 | 
				
			||||||
| 
						 | 
					@ -128,6 +157,22 @@ impl Lexer<'_> {
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
					_ => {
 | 
										_ => {
 | 
				
			||||||
 | 
											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)));
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
						debug!("got invalid char '{}'", val);
 | 
											debug!("got invalid char '{}'", val);
 | 
				
			||||||
						Err(ParseErr::Invalid)
 | 
											Err(ParseErr::Invalid)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
| 
						 | 
					@ -137,6 +182,16 @@ impl Lexer<'_> {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fn next(&mut self) -> Result<Token, ParseErr> {
 | 
				
			||||||
 | 
							let val = self.next_tok;
 | 
				
			||||||
 | 
							self.next_tok = self._next();
 | 
				
			||||||
 | 
							val
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fn peek(&mut self) -> Result<Token, ParseErr> {
 | 
				
			||||||
 | 
							self.next_tok
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO: replace with iterator so I can do parser.parse(lexer.iter()) and parse does lex_iter.next() & such
 | 
						// TODO: replace with iterator so I can do parser.parse(lexer.iter()) and parse does lex_iter.next() & such
 | 
				
			||||||
	fn lex_all(&mut self) -> Option<Vec<Token>> {
 | 
						fn lex_all(&mut self) -> Option<Vec<Token>> {
 | 
				
			||||||
		let mut tokens: Vec<Token> = vec![];
 | 
							let mut tokens: Vec<Token> = vec![];
 | 
				
			||||||
| 
						 | 
					@ -151,6 +206,16 @@ impl Lexer<'_> {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn matches(s: &str, check: &str) -> usize {
 | 
				
			||||||
 | 
						// debug!("s: \"{}\", check: \"{}\"c_len: {}, s_len: {}, s[c_len]: {:?}, s[c_len + 1]: {:?}", s, check, check.chars().count(), s.chars().count(), s.chars().nth(check.chars().count()), s.chars().nth(check.chars().count() + 1));
 | 
				
			||||||
 | 
						match (s.chars().count(), check.chars().count()) {
 | 
				
			||||||
 | 
							(s_len, c_len) if s_len < c_len => 0,
 | 
				
			||||||
 | 
							(s_len, c_len) if s_len == c_len && s == check => c_len - 1,
 | 
				
			||||||
 | 
							(s_len, c_len) if s_len > c_len && s.starts_with(check) && s.chars().nth(c_len).unwrap().is_whitespace() => c_len,
 | 
				
			||||||
 | 
							(_, _) => 0,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Parser<'a> {
 | 
					struct Parser<'a> {
 | 
				
			||||||
	lex: Lexer<'a>,
 | 
						lex: Lexer<'a>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -173,27 +238,33 @@ impl Parser<'_> {
 | 
				
			||||||
				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::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),
 | 
										_ => Err(ParseErr::Invalid),
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			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);
 | 
				
			||||||
		loop {
 | 
							loop {
 | 
				
			||||||
			let op: Op = match self.lex.next() {
 | 
								let op: Op = match self.lex.peek() {
 | 
				
			||||||
				Err(ParseErr::Eof) => break,
 | 
									Err(ParseErr::Eof) => break,
 | 
				
			||||||
				Err(e) => return 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::BinOp(op) => match op {
 | 
				
			||||||
							BinOp::RParen => break,
 | 
												BinOp::RParen => break,
 | 
				
			||||||
							_ => Ok(Op::BinOp(op)),
 | 
												_ => Ok(Op::BinOp(op)),
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
						Op::Func(f) => Ok(Op::Func(f)),
 | 
											Op::Func(f) => {
 | 
				
			||||||
 | 
												lhs = Expr::Node(Op::Func(f), vec![self.parse_expr(Op::Func(f).get_lbp())?]);
 | 
				
			||||||
 | 
												continue;
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					_ => Err(ParseErr::Invalid),
 | 
										v => { debug!("Got unexpected token {:?}", v); Err(ParseErr::Invalid) },
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}.map_err(|err| { debug!("Unexpected error inside expr: {:?}", err); err })?;
 | 
								}.map_err(|err| { debug!("Unexpected error inside expr at {:?}", err); err })?;
 | 
				
			||||||
			if (op.get_lbp() < min_bp) { break; }
 | 
								if (op.get_lbp() < min_bp) { break; }
 | 
				
			||||||
 | 
								self.lex.next();
 | 
				
			||||||
			let rhs: Expr = self.parse_expr(op.get_rbp())?;
 | 
								let rhs: Expr = self.parse_expr(op.get_rbp())?;
 | 
				
			||||||
			lhs = Expr::Node(op, vec![lhs, rhs]);
 | 
								lhs = Expr::Node(op, vec![lhs, rhs]);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -201,16 +272,6 @@ impl Parser<'_> {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*#[derive(Debug)]
 | 
					 | 
				
			||||||
enum Op {
 | 
					 | 
				
			||||||
	Add(Expr, Expr),
 | 
					 | 
				
			||||||
	Sub(Expr, Expr),
 | 
					 | 
				
			||||||
	Mul(Expr, Expr),
 | 
					 | 
				
			||||||
	Div(Expr, Expr),
 | 
					 | 
				
			||||||
	Func(Func, Expr),
 | 
					 | 
				
			||||||
}*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: look at that parser video again
 | 
					 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
enum Expr {
 | 
					enum Expr {
 | 
				
			||||||
	Atom(Atom),
 | 
						Atom(Atom),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue