From 24d056b19844535fdaffd30313dc4bfe6177b950 Mon Sep 17 00:00:00 2001 From: John Doty Date: Mon, 1 Jan 2024 08:30:30 -0800 Subject: [PATCH] [fine] Fix bugs, testing --- oden-script/src/parser.rs | 53 +++++++++++++++++++++++++++++++++------ oden-script/src/tokens.rs | 16 ++---------- 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/oden-script/src/parser.rs b/oden-script/src/parser.rs index 61283f73..e05c9a84 100644 --- a/oden-script/src/parser.rs +++ b/oden-script/src/parser.rs @@ -184,6 +184,7 @@ impl<'a> Parser<'a> { } fn expression_with_power(&mut self, minimum_power: u8) -> ExprRef { + self.trace("expression with power"); self.advance(); let mut expr = self.prefix_expression(); loop { @@ -203,6 +204,7 @@ impl<'a> Parser<'a> { } fn prefix_expression(&mut self) -> ExprRef { + self.trace("prefix"); let token = self.previous.as_ref(); match token { Some(token) => match token.kind() { @@ -222,6 +224,7 @@ impl<'a> Parser<'a> { } fn infix_expression(&mut self, power: u8, left: ExprRef) -> ExprRef { + self.trace("infix"); let kind = self.previous.as_ref().unwrap().kind(); match kind { TokenKind::Plus | TokenKind::Minus | TokenKind::Star | TokenKind::Slash => { @@ -245,7 +248,7 @@ impl<'a> Parser<'a> { } fn grouping(&mut self) -> ExprRef { - let result = self.number(); + let result = self.expression(); self.consume( Some(TokenKind::RightParen), "expected ')' after an expression", @@ -264,7 +267,6 @@ impl<'a> Parser<'a> { } fn binary(&mut self, power: u8, left: ExprRef) -> ExprRef { - let right = self.expression_with_power(power + 1); let op = match self.previous.as_ref().unwrap().kind() { TokenKind::Plus => BinaryOp::Add, TokenKind::Minus => BinaryOp::Subtract, @@ -274,6 +276,7 @@ impl<'a> Parser<'a> { TokenKind::Or => BinaryOp::Or, _ => panic!("unsuitable binary: {:?}: no op", self.previous), }; + let right = self.expression_with_power(power + 1); self.tree.add_expr(Expr::Binary(op, left, right)) } @@ -343,6 +346,24 @@ impl<'a> Parser<'a> { self.tree .add_error(SyntaxError::new(line, column, final_message)); } + + fn trace(&self, _msg: &str) { + // let cpos = self.tokens.token_position(&self.current); + // let ppos = self.tokens.token_position(&self.previous); + + // eprintln!( + // "[{}:{}:{}] [{}:{}:{}]: {msg}", + // ppos.0, + // ppos.1, + // self.previous + // .as_ref() + // .map(|t| t.as_str()) + // .unwrap_or(""), + // cpos.0, + // cpos.1, + // self.current.as_ref().map(|t| t.as_str()).unwrap_or("") + // ); + } } #[cfg(test)] @@ -350,11 +371,27 @@ mod tests { use super::*; use pretty_assertions::assert_eq; - #[test] - pub fn number_expressions() { - // How am I going to test this? - let (tree, expr) = Parser::new("23.5").parse(); - assert_eq!(Vec::::new(), tree.errors); - assert_eq!("23.5", tree.dump_expr(&expr)); + fn test_successful_expression_parse(source: &str, expected: &str) { + let (tree, expr) = Parser::new(source).parse(); + assert_eq!( + Vec::::new(), + tree.errors, + "Expected successful parse" + ); + assert_eq!(expected, tree.dump_expr(&expr)); } + + macro_rules! test_expr { + ($name:ident, $input:expr, $expected:expr) => { + #[test] + fn $name() { + test_successful_expression_parse($input, $expected); + } + }; + } + + test_expr!(number_expr, "12", "12"); + test_expr!(add_expr, "1 + 2", "(+ 1 2)"); + test_expr!(prec_expr, "1 + 2 * 3 - 7 * 7", "(- (+ 1 (* 2 3)) (* 7 7))"); + test_expr!(unary, "-((23)) * 5", "(* (- 23) 5)"); } diff --git a/oden-script/src/tokens.rs b/oden-script/src/tokens.rs index d0df5685..2a09336e 100644 --- a/oden-script/src/tokens.rs +++ b/oden-script/src/tokens.rs @@ -391,20 +391,8 @@ impl<'a> std::iter::Iterator for Tokens<'a> { ')' => self.token(pos, TokenKind::RightParen), ',' => self.token(pos, TokenKind::Comma), '.' => self.token(pos, TokenKind::Dot), - '-' => { - if self.matches_next(|c| c.is_ascii_digit()) { - self.number(pos) - } else { - self.token(pos, TokenKind::Minus) - } - } - '+' => { - if self.matches_next(|c| c.is_ascii_digit()) { - self.number(pos) - } else { - self.token(pos, TokenKind::Plus) - } - } + '-' => self.token(pos, TokenKind::Minus), + '+' => self.token(pos, TokenKind::Plus), ';' => self.token(pos, TokenKind::Semicolon), '/' => self.token(pos, TokenKind::Slash), '*' => self.token(pos, TokenKind::Star),