fix: Recover from missing argument in call expressions

Previously, when parsing an argument list with a missing argument (e.g.,
`(a, , b)` in `foo(a, , b)`), the parser would stop upon an unexpected
token (at the second comma in the example), resulting in an incorrect
parse tree.

This commit improves error handling in such cases, ensuring a more
accurate parse tree is built.
This commit is contained in:
Yutaro Ohno 2023-12-08 19:05:27 +09:00 committed by Lukas Wirth
parent bcc8a09a0d
commit e865d45904
4 changed files with 53 additions and 22 deletions

View file

@ -611,6 +611,7 @@ fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
// foo(bar::);
// foo(bar:);
// foo(bar+);
// foo(a, , b);
// }
fn arg_list(p: &mut Parser<'_>) {
assert!(p.at(T!['(']));
@ -619,14 +620,30 @@ fn arg_list(p: &mut Parser<'_>) {
// fn main() {
// foo(#[attr] 92)
// }
delimited(
p,
T!['('],
T![')'],
T![,],
EXPR_FIRST.union(ATTRIBUTE_FIRST),
|p: &mut Parser<'_>| expr(p).is_some(),
);
p.bump(T!['(']);
while !p.at(T![')']) && !p.at(EOF) {
if p.at(T![,]) {
// Recover if an argument is missing and only got a delimiter,
// e.g. `(a, , b)`.
p.error("expected expression");
p.bump(T![,]);
continue;
}
if expr(p).is_none() {
break;
}
if !p.at(T![,]) {
if p.at_ts(EXPR_FIRST.union(ATTRIBUTE_FIRST)) {
p.error(format!("expected {:?}", T![,]));
} else {
break;
}
} else {
p.bump(T![,]);
}
}
p.expect(T![')']);
m.complete(p, ARG_LIST);
}