[fine] Fix bugs, testing
This commit is contained in:
parent
ece5576fb2
commit
24d056b198
2 changed files with 47 additions and 22 deletions
|
|
@ -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)");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue