From 1c2acd121cb043f4a9d640a1e096287f6f5fa110 Mon Sep 17 00:00:00 2001 From: Boshen Date: Tue, 4 Apr 2023 22:36:35 +0800 Subject: [PATCH] refactor(parser): clean up parsing of ForStatement (#251) closes #176 --- crates/oxc_parser/src/js/statement.rs | 47 ++++++++++++--------------- tasks/coverage/test262.snap | 23 +++++++------ 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/crates/oxc_parser/src/js/statement.rs b/crates/oxc_parser/src/js/statement.rs index 514d91104..ffd6b78f9 100644 --- a/crates/oxc_parser/src/js/statement.rs +++ b/crates/oxc_parser/src/js/statement.rs @@ -241,17 +241,12 @@ impl<'a> Parser<'a> { { let start_span = self.start_span(); let init_declaration = self.without_context(Context::In, |p| { - p.parse_variable_declaration( - start_span, - VariableDeclarationContext::new(VariableDeclarationParent::For), - Modifiers::empty(), - ) + let decl_ctx = VariableDeclarationContext::new(VariableDeclarationParent::For); + p.parse_variable_declaration(start_span, decl_ctx, Modifiers::empty()) })?; - let kind = self.cur_kind(); - // for (.. a in) for (.. a of) - if matches!(kind, Kind::In | Kind::Of) { + if matches!(self.cur_kind(), Kind::In | Kind::Of) { let init = ForStatementLeft::VariableDeclaration(init_declaration); return self.parse_for_in_or_of_loop(span, r#await, init); } @@ -263,24 +258,25 @@ impl<'a> Parser<'a> { let is_let_of = self.at(Kind::Let) && self.peek_at(Kind::Of); let is_async_of = self.at(Kind::Async) && !self.cur_token().escaped && self.peek_at(Kind::Of); - let expression_span = self.start_span(); + let expr_span = self.start_span(); + + if self.at(Kind::RParen) { + return self.parse_for_loop(span, None, r#await); + } let init_expression = self.without_context(Context::In, Parser::parse_expression)?; // for (a.b in ...), for ([a] in ..), for ({a} in ..) if self.at(Kind::In) || self.at(Kind::Of) { let target = AssignmentTarget::cover(init_expression, self) - .map_err(|_| diagnostics::UnexpectedToken(self.end_span(expression_span)))?; + .map_err(|_| diagnostics::UnexpectedToken(self.end_span(expr_span)))?; let for_stmt_left = ForStatementLeft::AssignmentTarget(target); - if !r#await && is_async_of { - self.error(diagnostics::ForLoopAsyncOf(self.end_span(expression_span))); + self.error(diagnostics::ForLoopAsyncOf(self.end_span(expr_span))); } - if is_let_of { - self.error(diagnostics::UnexpectedKeyword("let", self.end_span(expression_span))); + self.error(diagnostics::UnexpectedKeyword("let", self.end_span(expr_span))); } - return self.parse_for_in_or_of_loop(span, r#await, for_stmt_left); } @@ -294,23 +290,22 @@ impl<'a> Parser<'a> { r#await: bool, ) -> Result> { self.expect(Kind::Semicolon)?; - let test = (!self.at(Kind::Semicolon)) - .then(|| self.parse_expression()) - .transpose() - .map_err(|_| { - let range = self.cur_token().span(); - diagnostics::ExpectToken(Kind::Semicolon.to_str(), self.cur_kind().to_str(), range) - })?; + let test = if !self.at(Kind::Semicolon) && !self.at(Kind::RParen) { + Some(self.with_context(Context::In, Parser::parse_expression)?) + } else { + None + }; self.expect(Kind::Semicolon)?; - let update = (!self.at(Kind::RParen)).then(|| self.parse_expression()).transpose()?; + let update = if self.at(Kind::RParen) { + None + } else { + Some(self.with_context(Context::In, Parser::parse_expression)?) + }; self.expect(Kind::RParen)?; - if r#await { self.error(diagnostics::ForAwait(self.end_span(span))); } - let body = self.parse_statement_list_item(StatementContext::For)?; - Ok(self.ast.for_statement(self.end_span(span), init, test, update, body)) } diff --git a/tasks/coverage/test262.snap b/tasks/coverage/test262.snap index 714b9d508..fbf388845 100644 --- a/tasks/coverage/test262.snap +++ b/tasks/coverage/test262.snap @@ -263,27 +263,30 @@ Negative Passed: 3915/3915 (100.00%) 21 │ break; ╰──── - × Unexpected token + × Expected `;` but found `)` ╭─[language/asi/S7.9_A6.3_T1.js:19:1] 19 │ for( 20 │ ) { - · ─ + · ┬ + · ╰── `;` expected 21 │ break; ╰──── - × Unexpected token + × Expected `;` but found `)` ╭─[language/asi/S7.9_A6.3_T2.js:20:1] 20 │ 21 │ ) { - · ─ + · ┬ + · ╰── `;` expected 22 │ break; ╰──── - × Unexpected token + × Expected `;` but found `)` ╭─[language/asi/S7.9_A6.3_T3.js:21:1] 21 │ 22 │ ) { - · ─ + · ┬ + · ╰── `;` expected 23 │ break; ╰──── @@ -30849,12 +30852,12 @@ Negative Passed: 3915/3915 (100.00%) 22 │ // ╰──── - × Expected `;` but found `++` + × Expected `,` but found `++` ╭─[language/statements/for/S12.6.3_A8.1_T2.js:20:1] 20 │ //CHECK#1 21 │ for(var index=0; {index++;index<100;}; index*2;) { arr.add(""+index);}; · ─┬ - · ╰── `;` expected + · ╰── `,` expected 22 │ // ╰──── @@ -30875,12 +30878,12 @@ Negative Passed: 3915/3915 (100.00%) 22 │ // ╰──── - × Expected `;` but found `++` + × Expected `,` but found `++` ╭─[language/statements/for/S12.6.3_A8_T2.js:20:1] 20 │ //CHECK#1 21 │ for(index=0; {index++;index<100;}; index*2;) { arr.add(""+index);}; · ─┬ - · ╰── `;` expected + · ╰── `,` expected 22 │ // ╰────