[fine] Fix bugs, testing

This commit is contained in:
John Doty 2024-01-01 08:30:30 -08:00
parent ece5576fb2
commit 24d056b198
2 changed files with 47 additions and 22 deletions

View file

@ -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("<eof>"),
// cpos.0,
// cpos.1,
// self.current.as_ref().map(|t| t.as_str()).unwrap_or("<eof>")
// );
}
}
#[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::<SyntaxError>::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::<SyntaxError>::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)");
}

View file

@ -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),