[fine] Working on parser resilience

This commit is contained in:
John Doty 2024-01-21 09:23:20 -08:00
parent 11cb7199e9
commit 741a729f8d
5 changed files with 129 additions and 1 deletions

View file

@ -395,6 +395,15 @@ impl<'a> CParser<'a> {
// eprintln!("{}: {}: {}", self.current.start, self.current, msg);
// }
fn at_any(&self, kinds: &[TokenKind]) -> bool {
for kind in kinds {
if self.at(*kind) {
return true;
}
}
return false;
}
fn at(&self, kind: TokenKind) -> bool {
self.peek() == kind
}
@ -586,6 +595,8 @@ fn field_decl(p: &mut CParser) {
p.end(m, TreeKind::FieldDecl);
}
const PARAM_LIST_RECOVERY: &[TokenKind] = &[TokenKind::Arrow, TokenKind::LeftBrace, TokenKind::Fun];
fn param_list(p: &mut CParser) {
let m = p.start();
@ -594,7 +605,10 @@ fn param_list(p: &mut CParser) {
if p.at(TokenKind::Identifier) {
parameter(p);
} else {
break;
if p.at_any(PARAM_LIST_RECOVERY) {
break;
}
p.advance_with_error("expected parameter");
}
}
p.expect(TokenKind::RightParen, "expect ')' to end a parameter list");

View file

@ -0,0 +1,4 @@
These tests all produce errors in their parse, but the point is that
the trees are kinda as best as we can get.
See e.g. https://matklad.github.io/2023/05/21/resilient-ll-parsing-tutorial.html

View file

@ -0,0 +1,53 @@
fun f1(x: f64,
fun f2(x: f64,, z: f64) {}
fun f3() {}
// @concrete:
// | File
// | FunctionDecl
// | Fun:'"fun"'
// | Identifier:'"f1"'
// | ParamList
// | LeftParen:'"("'
// | Parameter
// | Identifier:'"x"'
// | Colon:'":"'
// | TypeExpression
// | Identifier:'"f64"'
// | Comma:'","'
// | Error:'"Error at 'fun': expect ')' to end a parameter list"'
// | FunctionDecl
// | Fun:'"fun"'
// | Identifier:'"f2"'
// | ParamList
// | LeftParen:'"("'
// | Parameter
// | Identifier:'"x"'
// | Colon:'":"'
// | TypeExpression
// | Identifier:'"f64"'
// | Comma:'","'
// | Error
// | Error:'"Error at ',': expected parameter"'
// | Comma:'","'
// | Parameter
// | Identifier:'"z"'
// | Colon:'":"'
// | TypeExpression
// | Identifier:'"f64"'
// | RightParen:'")"'
// | Block
// | LeftBrace:'"{"'
// | RightBrace:'"}"'
// | FunctionDecl
// | Fun:'"fun"'
// | Identifier:'"f3"'
// | ParamList
// | LeftParen:'"("'
// | RightParen:'")"'
// | Block
// | LeftBrace:'"{"'
// | RightBrace:'"}"'
//

View file

@ -0,0 +1,57 @@
fun fib_rec(f1: f64,
fun fib(n: f64) -> f64 {
fib_rec(1, 1, n)
}
// @concrete:
// | File
// | FunctionDecl
// | Fun:'"fun"'
// | Identifier:'"fib_rec"'
// | ParamList
// | LeftParen:'"("'
// | Parameter
// | Identifier:'"f1"'
// | Colon:'":"'
// | TypeExpression
// | Identifier:'"f64"'
// | Comma:'","'
// | Error:'"Error at 'fun': expect ')' to end a parameter list"'
// | FunctionDecl
// | Fun:'"fun"'
// | Identifier:'"fib"'
// | ParamList
// | LeftParen:'"("'
// | Parameter
// | Identifier:'"n"'
// | Colon:'":"'
// | TypeExpression
// | Identifier:'"f64"'
// | RightParen:'")"'
// | ReturnType
// | Arrow:'"->"'
// | TypeExpression
// | Identifier:'"f64"'
// | Block
// | LeftBrace:'"{"'
// | ExpressionStatement
// | CallExpression
// | Identifier
// | Identifier:'"fib_rec"'
// | ArgumentList
// | LeftParen:'"("'
// | Argument
// | LiteralExpression
// | Number:'"1"'
// | Comma:'","'
// | Argument
// | LiteralExpression
// | Number:'"1"'
// | Comma:'","'
// | Argument
// | Identifier
// | Identifier:'"n"'
// | RightParen:'")"'
// | RightBrace:'"}"'
//