From 11cb7199e97e91742f943ed62f1c841c2b029a90 Mon Sep 17 00:00:00 2001 From: John Doty Date: Sun, 21 Jan 2024 09:01:12 -0800 Subject: [PATCH] [fine] Fix a problem with a stuck parser Whoops --- fine/src/parser.rs | 27 ++++++++++++++++--- fine/tests/errors/unbalanced_right_brace.fine | 20 ++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 fine/tests/errors/unbalanced_right_brace.fine diff --git a/fine/src/parser.rs b/fine/src/parser.rs index 962a2b3c..0c4a8800 100644 --- a/fine/src/parser.rs +++ b/fine/src/parser.rs @@ -361,7 +361,7 @@ impl<'a> CParser<'a> { fn advance(&mut self) { assert!(!self.eof()); // Don't try to advance past EOF - self.fuel.set(256); // Consuming a token, rest stuck detector + self.fuel.set(256); // Consuming a token, reset stuck detector self.events.push(ParseEvent::Advance { token: self.current.clone(), }); @@ -381,11 +381,20 @@ impl<'a> CParser<'a> { } fn peek(&self) -> TokenKind { - assert!(self.fuel.get() > 0, "parser is stuck!"); + if self.fuel.get() == 0 { + panic!( + "parser is stuck at '{}' ({})!", + self.current, self.current.start + ); + } self.fuel.set(self.fuel.get() - 1); self.current.kind } + // fn trace(&self, msg: &str) { + // eprintln!("{}: {}: {}", self.current.start, self.current, msg); + // } + fn at(&self, kind: TokenKind) -> bool { self.peek() == kind } @@ -511,6 +520,14 @@ fn file(p: &mut CParser) { while !p.eof() { match p.peek() { TokenKind::Class => class(p), + TokenKind::RightBrace => { + // An error parsing mismatched braces can leave me at an + // un-balanced right brace, which unfortunately will not be + // consumed by the statement below. (Statement currently + // falls through to expression_statement, which checks for + // the right-brace that a block would end with.) + p.advance_with_error("unbalanced '}'"); + } _ => statement(p), } } @@ -542,7 +559,11 @@ fn class(p: &mut CParser) { p.expect(TokenKind::Identifier, "expected a class name"); if p.eat(TokenKind::LeftBrace) { while !p.at(TokenKind::RightBrace) && !p.eof() { - field_decl(p); + if p.at(TokenKind::Identifier) { + field_decl(p); + } else { + p.advance_with_error("expected a field declaration"); + } } } p.expect(TokenKind::RightBrace, "expected a class to end with a '}'"); diff --git a/fine/tests/errors/unbalanced_right_brace.fine b/fine/tests/errors/unbalanced_right_brace.fine new file mode 100644 index 00000000..f1926639 --- /dev/null +++ b/fine/tests/errors/unbalanced_right_brace.fine @@ -0,0 +1,20 @@ +fun foo() { } + +} // <- Whoopsie! + +// @concrete: +// | File +// | FunctionDecl +// | Fun:'"fun"' +// | Identifier:'"foo"' +// | ParamList +// | LeftParen:'"("' +// | RightParen:'")"' +// | Block +// | LeftBrace:'"{"' +// | RightBrace:'"}"' +// | Error +// | Error:'"Error at '}': unbalanced '}'"' +// | RightBrace:'"}"' +// | +//