diff --git a/fine/src/parser.rs b/fine/src/parser.rs index 1e0101c5..e8bd273d 100644 --- a/fine/src/parser.rs +++ b/fine/src/parser.rs @@ -430,7 +430,7 @@ impl<'a> CParser<'a> { } fn expect_start(&mut self, kind: TokenKind) { - assert!(self.eat(kind)); + assert!(self.eat(kind), "should have started with {kind:?}"); } fn advance_with_error(&mut self, error: T) -> MarkClosed @@ -708,7 +708,7 @@ fn block(p: &mut CParser) { while !p.at(TokenKind::RightBrace) && !p.eof() { statement(p); } - p.expect(TokenKind::RightBrace, "expect '}' to start a block"); + p.expect(TokenKind::RightBrace, "expect '}' to end a block"); p.end(m, TreeKind::Block); } @@ -756,6 +756,7 @@ fn statement_return(p: &mut CParser) { let m = p.start(); p.expect_start(TokenKind::Return); + // TODO: Make expression optional if we're returning () expression(p); if !p.at(TokenKind::RightBrace) { p.expect(TokenKind::Semicolon, "expect ';' to end a return statement"); @@ -938,13 +939,19 @@ fn conditional(p: &mut CParser) -> MarkClosed { p.expect_start(TokenKind::If); expression(p); - block(p); + if p.at(TokenKind::LeftBrace) { + block(p) + } else { + p.error("expected a block after `if`") + } if p.eat(TokenKind::Else) { if p.at(TokenKind::If) { // Don't require another block, just jump right into the conditional. conditional(p); - } else { + } else if p.at(TokenKind::LeftBrace) { block(p); + } else { + p.error("expected a block after `else`") } } diff --git a/fine/tests/expression/errors/broken_conditional.fine b/fine/tests/expression/errors/broken_conditional.fine new file mode 100644 index 00000000..84efd0cb --- /dev/null +++ b/fine/tests/expression/errors/broken_conditional.fine @@ -0,0 +1,8 @@ +fun test() { + if true true { } +} + +// NOTE: These errors should be better +// @expect-errors: +// | 2:10: Error at 'true': expected a block after `if` +// | 2:15: Error at '{': expect ';' to end an expression statement