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

@ -631,20 +631,6 @@ fn foo() {
)
}
#[test]
fn extraneous_comma() {
check(
r#"
fn foo() {
bar(,);
}
"#,
expect![[r#"
fn foo () {__ra_fixup ;}
"#]],
)
}
#[test]
fn fixup_if_1() {
check(

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);
}

View File

@ -68,6 +68,32 @@ SOURCE_FILE
PLUS "+"
R_PAREN ")"
SEMICOLON ";"
WHITESPACE "\n "
EXPR_STMT
CALL_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "foo"
ARG_LIST
L_PAREN "("
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "a"
COMMA ","
WHITESPACE " "
COMMA ","
WHITESPACE " "
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "b"
R_PAREN ")"
SEMICOLON ";"
WHITESPACE "\n"
R_CURLY "}"
WHITESPACE "\n"
@ -75,3 +101,4 @@ error 25: expected identifier
error 39: expected COMMA
error 39: expected expression
error 55: expected expression
error 68: expected expression

View File

@ -2,4 +2,5 @@ fn main() {
foo(bar::);
foo(bar:);
foo(bar+);
foo(a, , b);
}