Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ use crate::{

impl<'a> ParserImpl<'a> {
pub(crate) fn parse_paren_expression(&mut self) -> Expression<'a> {
let opening_span = self.cur_token().span();
self.expect(Kind::LParen);
let expression = self.parse_expr();
self.expect(Kind::RParen);
self.expect_closing(Kind::RParen, opening_span);
expression
}

Expand Down
56 changes: 43 additions & 13 deletions crates/oxc_parser/src/js/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,12 @@ impl<'a> ParserImpl<'a> {
false
};

let parenthesis_opening_span = self.cur_token().span();
self.expect(Kind::LParen);

// for (;..
if self.at(Kind::Semicolon) {
return self.parse_for_loop(span, None, r#await);
return self.parse_for_loop(span, parenthesis_opening_span, None, r#await);
}

// `for (const` | `for (var`
Expand All @@ -318,6 +319,7 @@ impl<'a> ParserImpl<'a> {
return self.parse_variable_declaration_for_statement(
span,
start_span,
parenthesis_opening_span,
VariableDeclarationKind::Const,
r#await,
);
Expand All @@ -328,6 +330,7 @@ impl<'a> ParserImpl<'a> {
return self.parse_variable_declaration_for_statement(
span,
start_span,
parenthesis_opening_span,
VariableDeclarationKind::Var,
r#await,
);
Expand All @@ -342,6 +345,7 @@ impl<'a> ParserImpl<'a> {
return self.parse_variable_declaration_for_statement(
span,
start_span,
parenthesis_opening_span,
VariableDeclarationKind::Let,
r#await,
);
Expand All @@ -363,7 +367,11 @@ impl<'a> ParserImpl<'a> {
!p.cur_token().is_on_new_line()
})
{
return self.parse_using_declaration_for_statement(span, r#await);
return self.parse_using_declaration_for_statement(
span,
parenthesis_opening_span,
r#await,
);
}

// [+Using] using [no LineTerminator here] ForBinding[?Yield, ?Await, ~Pattern]
Expand All @@ -372,11 +380,15 @@ impl<'a> ParserImpl<'a> {
let kind = token.kind();
!token.is_on_new_line() && kind != Kind::Of && kind.is_binding_identifier()
} {
return self.parse_using_declaration_for_statement(span, r#await);
return self.parse_using_declaration_for_statement(
span,
parenthesis_opening_span,
r#await,
);
}

if self.at(Kind::RParen) {
return self.parse_for_loop(span, None, r#await);
return self.parse_for_loop(span, parenthesis_opening_span, None, r#await);
}

let is_let = self.at(Kind::Let);
Expand All @@ -390,7 +402,7 @@ impl<'a> ParserImpl<'a> {
Kind::In => {
let target = AssignmentTarget::cover(init_expression, self);
let for_stmt_left = ForStatementLeft::from(target);
self.parse_for_in_loop(span, r#await, for_stmt_left)
self.parse_for_in_loop(span, parenthesis_opening_span, r#await, for_stmt_left)
}
Kind::Of => {
if !r#await && is_async && init_expression.is_identifier_reference() {
Expand All @@ -403,16 +415,22 @@ impl<'a> ParserImpl<'a> {
}
let target = AssignmentTarget::cover(init_expression, self);
let for_stmt_left = ForStatementLeft::from(target);
self.parse_for_of_loop(span, r#await, for_stmt_left)
self.parse_for_of_loop(span, parenthesis_opening_span, r#await, for_stmt_left)
}
_ => self.parse_for_loop(span, Some(ForStatementInit::from(init_expression)), r#await),
_ => self.parse_for_loop(
span,
parenthesis_opening_span,
Some(ForStatementInit::from(init_expression)),
r#await,
),
}
}

fn parse_variable_declaration_for_statement(
&mut self,
span: u32,
start_span: u32,
parenthesis_opening_span: Span,
decl_kind: VariableDeclarationKind,
r#await: bool,
) -> Statement<'a> {
Expand All @@ -425,7 +443,7 @@ impl<'a> ParserImpl<'a> {
)
});

self.parse_any_for_loop(span, init_declaration, r#await)
self.parse_any_for_loop(span, parenthesis_opening_span, init_declaration, r#await)
}

pub(crate) fn is_using_declaration(&mut self) -> bool {
Expand All @@ -434,7 +452,12 @@ impl<'a> ParserImpl<'a> {
(kind.is_binding_identifier() || kind == Kind::LCurly) && !token.is_on_new_line()
}

fn parse_using_declaration_for_statement(&mut self, span: u32, r#await: bool) -> Statement<'a> {
fn parse_using_declaration_for_statement(
&mut self,
span: u32,
parenthesis_opening_span: Span,
r#await: bool,
) -> Statement<'a> {
let using_decl = self.parse_using_declaration(StatementContext::For);

if matches!(self.cur_kind(), Kind::In) {
Expand All @@ -450,28 +473,32 @@ impl<'a> ParserImpl<'a> {
}

let init_declaration = self.alloc(using_decl);
self.parse_any_for_loop(span, init_declaration, r#await)
self.parse_any_for_loop(span, parenthesis_opening_span, init_declaration, r#await)
}

fn parse_any_for_loop(
&mut self,
span: u32,
parenthesis_opening_span: Span,
init_declaration: Box<'a, VariableDeclaration<'a>>,
r#await: bool,
) -> Statement<'a> {
match self.cur_kind() {
Kind::In => self.parse_for_in_loop(
span,
parenthesis_opening_span,
r#await,
ForStatementLeft::VariableDeclaration(init_declaration),
),
Kind::Of => self.parse_for_of_loop(
span,
parenthesis_opening_span,
r#await,
ForStatementLeft::VariableDeclaration(init_declaration),
),
_ => self.parse_for_loop(
span,
parenthesis_opening_span,
Some(ForStatementInit::VariableDeclaration(init_declaration)),
r#await,
),
Expand All @@ -481,6 +508,7 @@ impl<'a> ParserImpl<'a> {
fn parse_for_loop(
&mut self,
span: u32,
parenthesis_opening_span: Span,
init: Option<ForStatementInit<'a>>,
r#await: bool,
) -> Statement<'a> {
Expand All @@ -501,7 +529,7 @@ impl<'a> ParserImpl<'a> {
} else {
Some(self.context_add(Context::In, ParserImpl::parse_expr))
};
self.expect(Kind::RParen);
self.expect_closing(Kind::RParen, parenthesis_opening_span);
if r#await {
self.error(diagnostics::for_await(self.end_span(span)));
}
Expand All @@ -512,12 +540,13 @@ impl<'a> ParserImpl<'a> {
fn parse_for_in_loop(
&mut self,
span: u32,
parenthesis_opening_span: Span,
r#await: bool,
left: ForStatementLeft<'a>,
) -> Statement<'a> {
self.bump_any(); // bump `in`
let right = self.parse_expr();
self.expect(Kind::RParen);
self.expect_closing(Kind::RParen, parenthesis_opening_span);

if r#await {
self.error(diagnostics::for_await(self.end_span(span)));
Expand All @@ -531,12 +560,13 @@ impl<'a> ParserImpl<'a> {
fn parse_for_of_loop(
&mut self,
span: u32,
parenthesis_opening_span: Span,
r#await: bool,
left: ForStatementLeft<'a>,
) -> Statement<'a> {
self.bump_any(); // bump `of`
let right = self.parse_assignment_expression_or_higher();
self.expect(Kind::RParen);
self.expect_closing(Kind::RParen, parenthesis_opening_span);

let body = self.parse_statement_list_item(StatementContext::For);
let span = self.end_span(span);
Expand Down
30 changes: 18 additions & 12 deletions tasks/coverage/snapshots/parser_babel.snap
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,9 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026
× Expected `)` but found `of`
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/valid-for-await-using-binding-escaped-of-of/input.mjs:1:29]
1 │ for await (using \u006ff of of);
· ─┬
· ╰── `)` expected
· ┬ ─┬
· │ ╰── `)` expected
· ╰── Opened here
╰────

Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/valid-for-using-binding-escaped-of-of/input.js
Expand All @@ -400,8 +401,9 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026
× Expected `)` but found `of`
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/valid-for-using-binding-escaped-of-of/input.js:1:23]
1 │ for (using o\u0066 of of);
· ─┬
· ╰── `)` expected
· ┬ ─┬
· │ ╰── `)` expected
· ╰── Opened here
╰────

Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/valid-for-using-declaration-binding-of/input.js
Expand Down Expand Up @@ -3277,8 +3279,9 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
× Expected `)` but found `,`
╭─[babel/packages/babel-parser/test/fixtures/es2015/for-of/invalid-expr/input.js:1:16]
1 │ for (let x of y, z) {}
· ┬
· ╰── `)` expected
· ┬ ┬
· │ ╰── `)` expected
· ╰── Opened here
╰────

× The left-hand side of a `for...of` statement may not start with `let`
Expand Down Expand Up @@ -5823,8 +5826,9 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
× Expected `)` but found `;`
╭─[babel/packages/babel-parser/test/fixtures/es2017/async-functions/invalid-for-await-expression-init/input.js:1:23]
1 │ for (await o\u0066 [0];;);
· ┬
· ╰── `)` expected
· ┬ ┬
· │ ╰── `)` expected
· ╰── Opened here
╰────

× Async functions can only be declared at the top level or inside a block
Expand Down Expand Up @@ -9415,8 +9419,9 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
× Expected `)` but found `of`
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-for-await-using-binding-of-of/input.mjs:1:24]
1 │ for await (using of of of);
· ─┬
· ╰── `)` expected
· ┬ ─┬
· │ ╰── `)` expected
· ╰── Opened here
╰────

× The left-hand side of a for...in statement cannot be an using declaration.
Expand All @@ -9435,8 +9440,9 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
× Expected `)` but found `of`
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-for-using-binding-of-of/input.js:1:18]
1 │ for (using of of of);
· ─┬
· ╰── `)` expected
· ┬ ─┬
· │ ╰── `)` expected
· ╰── Opened here
╰────

× Unexpected token
Expand Down
Loading
Loading