Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
fix(rome_js_parser): improve await handling in non-async context (#3573)
Browse files Browse the repository at this point in the history
  • Loading branch information
95th authored Nov 14, 2022
1 parent 1bcaec4 commit 9b5dcdc
Show file tree
Hide file tree
Showing 14 changed files with 677 additions and 246 deletions.
43 changes: 31 additions & 12 deletions crates/rome_js_parser/src/syntax/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1821,7 +1821,7 @@ pub(super) fn parse_unary_expr(p: &mut Parser, context: ExpressionContext) -> Pa
const UNARY_SINGLE: TokenSet =
token_set![T![delete], T![void], T![typeof], T![+], T![-], T![~], T![!]];

if (p.state.in_async()) && p.at(T![await]) {
if p.at(T![await]) {
// test await_expression
// async function test() {
// await inner();
Expand All @@ -1837,32 +1837,51 @@ pub(super) fn parse_unary_expr(p: &mut Parser, context: ExpressionContext) -> Pa
// async function test() {}
// await test();
let m = p.start();
let checkpoint = p.checkpoint();
let await_range = p.cur_range();
p.expect(T![await]);
let unary = parse_unary_expr(p, context);

parse_unary_expr(p, context)
.or_add_diagnostic(p, js_parse_error::expected_unary_expression);
let is_top_level_module_or_async_fn =
p.state.in_async() && (p.state.is_top_level() || p.state.in_function());

let mut expr = m.complete(p, JS_AWAIT_EXPRESSION);
if !is_top_level_module_or_async_fn {
// test reparse_await_as_identifier
// // SCRIPT
// function test() { a = await; }
// function test2() { return await; }
if unary.is_absent() {
p.rewind(checkpoint);
m.abandon(p);
return parse_identifier_expression(p);
}

if !p.state.is_top_level() && !p.state.in_function() {
// test_err await_in_parameter_initializer
// async function test(a = await b()) {}
// function test2(a = await b()) {}

// test_err await_in_static_initialization_block_member
// // SCRIPT
// class A {
// static {
// await;
// }
// }
// class A { static { await; } }
// class B { static { await 10; } }

// test_err await_in_non_async_function
// function test() { await 10; }

// test_err await_in_module
// let await = 10;
// console.log(await);
p.error(p.err_builder(
"`await` is only allowed within async functions and at the top levels of modules.",
expr.range(p),
await_range,
));
expr.change_to_unknown(p);

let expr = m.complete(p, JS_UNKNOWN_EXPRESSION);
return Present(expr);
}

unary.or_add_diagnostic(p, js_parse_error::expected_unary_expression);
let expr = m.complete(p, JS_AWAIT_EXPRESSION);
return Present(expr);
}

Expand Down
1 change: 1 addition & 0 deletions crates/rome_js_parser/src/syntax/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,7 @@ fn parse_arrow_function_with_single_parameter(p: &mut Parser) -> ParsedSyntax {
// test_err async_arrow_expr_await_parameter
// let a = async await => {}
// async() => { (a = await) => {} };
// async() => { (a = await 10) => {} };
p.with_state(EnterParameters(arrow_function_parameter_flags(p, flags)), parse_binding)
.expect("Expected function parameter to be present as guaranteed by is_arrow_function_with_simple_parameter");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
let a = async await => {}
async() => { (a = await) => {} };
async() => { (a = await 10) => {} };
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ JsModule {
eq_token: EQ@42..44 "=" [] [Whitespace(" ")],
expression: JsUnknownExpression {
items: [
AWAIT_KW@44..49 "await" [] [],
JsUnknown {
items: [
IDENT@44..49 "await" [] [],
],
},
],
},
},
Expand All @@ -93,14 +97,74 @@ JsModule {
},
semicolon_token: SEMICOLON@58..59 ";" [] [],
},
JsExpressionStatement {
expression: JsArrowFunctionExpression {
async_token: ASYNC_KW@59..65 "async" [Newline("\n")] [],
type_parameters: missing (optional),
parameters: JsParameters {
l_paren_token: L_PAREN@65..66 "(" [] [],
items: JsParameterList [],
r_paren_token: R_PAREN@66..68 ")" [] [Whitespace(" ")],
},
return_type_annotation: missing (optional),
fat_arrow_token: FAT_ARROW@68..71 "=>" [] [Whitespace(" ")],
body: JsFunctionBody {
l_curly_token: L_CURLY@71..73 "{" [] [Whitespace(" ")],
directives: JsDirectiveList [],
statements: JsStatementList [
JsExpressionStatement {
expression: JsArrowFunctionExpression {
async_token: missing (optional),
type_parameters: missing (optional),
parameters: JsParameters {
l_paren_token: L_PAREN@73..74 "(" [] [],
items: JsParameterList [
JsFormalParameter {
binding: JsIdentifierBinding {
name_token: IDENT@74..76 "a" [] [Whitespace(" ")],
},
question_mark_token: missing (optional),
type_annotation: missing (optional),
initializer: JsInitializerClause {
eq_token: EQ@76..78 "=" [] [Whitespace(" ")],
expression: JsUnknownExpression {
items: [
AWAIT_KW@78..84 "await" [] [Whitespace(" ")],
JsNumberLiteralExpression {
value_token: JS_NUMBER_LITERAL@84..86 "10" [] [],
},
],
},
},
},
],
r_paren_token: R_PAREN@86..88 ")" [] [Whitespace(" ")],
},
return_type_annotation: missing (optional),
fat_arrow_token: FAT_ARROW@88..91 "=>" [] [Whitespace(" ")],
body: JsFunctionBody {
l_curly_token: L_CURLY@91..92 "{" [] [],
directives: JsDirectiveList [],
statements: JsStatementList [],
r_curly_token: R_CURLY@92..94 "}" [] [Whitespace(" ")],
},
},
semicolon_token: missing (optional),
},
],
r_curly_token: R_CURLY@94..95 "}" [] [],
},
},
semicolon_token: SEMICOLON@95..96 ";" [] [],
},
],
eof_token: EOF@59..60 "" [Newline("\n")] [],
eof_token: EOF@96..97 "" [Newline("\n")] [],
}

0: JS_MODULE@0..60
0: JS_MODULE@0..97
0: (empty)
1: JS_DIRECTIVE_LIST@0..0
2: JS_MODULE_ITEM_LIST@0..59
2: JS_MODULE_ITEM_LIST@0..96
0: JS_VARIABLE_STATEMENT@0..25
0: JS_VARIABLE_DECLARATION@0..25
0: LET_KW@0..4 "let" [] [Whitespace(" ")]
Expand Down Expand Up @@ -153,7 +217,8 @@ JsModule {
3: JS_INITIALIZER_CLAUSE@42..49
0: EQ@42..44 "=" [] [Whitespace(" ")]
1: JS_UNKNOWN_EXPRESSION@44..49
0: AWAIT_KW@44..49 "await" [] []
0: JS_UNKNOWN@44..49
0: IDENT@44..49 "await" [] []
2: R_PAREN@49..51 ")" [] [Whitespace(" ")]
3: (empty)
4: FAT_ARROW@51..54 "=>" [] [Whitespace(" ")]
Expand All @@ -165,7 +230,50 @@ JsModule {
1: (empty)
3: R_CURLY@57..58 "}" [] []
1: SEMICOLON@58..59 ";" [] []
3: EOF@59..60 "" [Newline("\n")] []
2: JS_EXPRESSION_STATEMENT@59..96
0: JS_ARROW_FUNCTION_EXPRESSION@59..95
0: ASYNC_KW@59..65 "async" [Newline("\n")] []
1: (empty)
2: JS_PARAMETERS@65..68
0: L_PAREN@65..66 "(" [] []
1: JS_PARAMETER_LIST@66..66
2: R_PAREN@66..68 ")" [] [Whitespace(" ")]
3: (empty)
4: FAT_ARROW@68..71 "=>" [] [Whitespace(" ")]
5: JS_FUNCTION_BODY@71..95
0: L_CURLY@71..73 "{" [] [Whitespace(" ")]
1: JS_DIRECTIVE_LIST@73..73
2: JS_STATEMENT_LIST@73..94
0: JS_EXPRESSION_STATEMENT@73..94
0: JS_ARROW_FUNCTION_EXPRESSION@73..94
0: (empty)
1: (empty)
2: JS_PARAMETERS@73..88
0: L_PAREN@73..74 "(" [] []
1: JS_PARAMETER_LIST@74..86
0: JS_FORMAL_PARAMETER@74..86
0: JS_IDENTIFIER_BINDING@74..76
0: IDENT@74..76 "a" [] [Whitespace(" ")]
1: (empty)
2: (empty)
3: JS_INITIALIZER_CLAUSE@76..86
0: EQ@76..78 "=" [] [Whitespace(" ")]
1: JS_UNKNOWN_EXPRESSION@78..86
0: AWAIT_KW@78..84 "await" [] [Whitespace(" ")]
1: JS_NUMBER_LITERAL_EXPRESSION@84..86
0: JS_NUMBER_LITERAL@84..86 "10" [] []
2: R_PAREN@86..88 ")" [] [Whitespace(" ")]
3: (empty)
4: FAT_ARROW@88..91 "=>" [] [Whitespace(" ")]
5: JS_FUNCTION_BODY@91..94
0: L_CURLY@91..92 "{" [] []
1: JS_DIRECTIVE_LIST@92..92
2: JS_STATEMENT_LIST@92..92
3: R_CURLY@92..94 "}" [] [Whitespace(" ")]
1: (empty)
3: R_CURLY@94..95 "}" [] []
1: SEMICOLON@95..96 ";" [] []
3: EOF@96..97 "" [Newline("\n")] []
--
async_arrow_expr_await_parameter.js:1:15 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Expand All @@ -174,35 +282,31 @@ async_arrow_expr_await_parameter.js:1:15 parse ━━━━━━━━━━━
> 1 │ let a = async await => {}
│ ^^^^^
2 │ async() => { (a = await) => {} };
3 │
3 │ async() => { (a = await 10) => {} };

--
async_arrow_expr_await_parameter.js:2:24 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async_arrow_expr_await_parameter.js:2:19 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× expected an unary expression but instead found ')'

1 │ let a = async await => {}
> 2 │ async() => { (a = await) => {} };
│ ^
3 │

i Expected an unary expression here
× Illegal use of `await` as an identifier in an async context

1 │ let a = async await => {}
> 2 │ async() => { (a = await) => {} };
│ ^
3 │
│ ^^^^^
3 │ async() => { (a = await 10) => {} };
4 │

--
async_arrow_expr_await_parameter.js:2:19 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async_arrow_expr_await_parameter.js:3:19 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× `await` is only allowed within async functions and at the top levels of modules.

1 │ let a = async await => {}
> 2 │ async() => { (a = await) => {} };
2 │ async() => { (a = await) => {} };
> 3 │ async() => { (a = await 10) => {} };
│ ^^^^^
3
4

--
let a = async await => {}
async() => { (a = await) => {} };
async() => { (a = await 10) => {} };
2 changes: 2 additions & 0 deletions crates/rome_js_parser/test_data/inline/err/await_in_module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
let await = 10;
console.log(await);
Loading

0 comments on commit 9b5dcdc

Please sign in to comment.