Skip to content

Commit

Permalink
Fix parsing of async in for-of loops
Browse files Browse the repository at this point in the history
  • Loading branch information
raskad committed Mar 18, 2024
1 parent f3dfd58 commit a6391e3
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 21 deletions.
19 changes: 13 additions & 6 deletions core/parser/src/parser/expression/assignment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,22 @@ where
1
};

let peek_1 = cursor.peek(1, interner).or_abrupt()?.kind().clone();
if !cursor
.peek_is_line_terminator(skip_n, interner)
.or_abrupt()?
&& matches!(
cursor.peek(1, interner).or_abrupt()?.kind(),
TokenKind::IdentifierName(_)
| TokenKind::Keyword((Keyword::Yield | Keyword::Await, _))
| TokenKind::Punctuator(Punctuator::OpenParen)
)
&& (matches!(peek_1, TokenKind::Punctuator(Punctuator::OpenParen))
|| (matches!(
peek_1,
TokenKind::IdentifierName(_)
| TokenKind::Keyword((
Keyword::Yield | Keyword::Await | Keyword::Of,
_
))
) && matches!(
cursor.peek(2, interner).or_abrupt()?.kind(),
TokenKind::Punctuator(Punctuator::Arrow)
)))
{
return Ok(
AsyncArrowFunction::new(self.name, self.allow_in, self.allow_yield)
Expand Down
26 changes: 25 additions & 1 deletion core/parser/src/parser/expression/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use boa_ast::{
},
Call, Identifier, Parenthesized, RegExpLiteral,
},
Declaration, Expression, Statement,
function::{AsyncArrowFunction, FormalParameter, FormalParameterList},
Declaration, Expression, Script, Statement,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
Expand Down Expand Up @@ -685,6 +686,29 @@ fn check_logical_expressions() {
check_invalid_script("a || b ?? c");
}

#[test]
fn parse_async_arrow_function_named_of() {
let interner = &mut Interner::default();
check_script_parser(
"async of => {}",
vec![
Statement::Expression(Expression::from(AsyncArrowFunction::new(
None,
FormalParameterList::from_parameters(vec![FormalParameter::new(
Variable::from_identifier(
Identifier::new(interner.get_or_intern_static("of", utf16!("of"))),
None,
),
false,
)]),
Script::default(),
)))
.into(),
],
interner,
);
}

macro_rules! check_non_reserved_identifier {
($keyword:literal) => {{
let interner = &mut Interner::default();
Expand Down
42 changes: 28 additions & 14 deletions core/parser/src/parser/statement/iteration/for_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ use crate::{
lexer::{Error as LexError, TokenKind},
parser::{
expression::{AssignmentExpression, Expression},
statement::declaration::LexicalDeclaration,
statement::{variable::VariableDeclarationList, Statement},
statement::{
declaration::LexicalDeclaration, variable::VariableDeclarationList, Statement,
},
AllowAwait, AllowReturn, AllowYield, Cursor, OrAbrupt, ParseResult, TokenParser,
},
source::ReadChar,
Error,
};
use ast::{
declaration::Binding,
expression::Identifier,
operations::{bound_names, var_declared_names},
};
use boa_ast::{
Expand Down Expand Up @@ -107,6 +109,7 @@ where
}
};

let mut init_is_async_of = false;
let init = match cursor.peek(0, interner).or_abrupt()?.kind() {
TokenKind::Keyword((Keyword::Var, _)) => {
cursor.advance(interner);
Expand Down Expand Up @@ -136,19 +139,18 @@ where
.into(),
),
TokenKind::Keyword((Keyword::Async, false)) if !r#await => {
match cursor.peek(1, interner).or_abrupt()?.kind() {
TokenKind::Keyword((Keyword::Of, _)) => {
return Err(Error::lex(LexError::Syntax(
"invalid left-hand side expression 'async' of a for-of loop".into(),
init_position,
)));
}
_ => Some(
Expression::new(None, false, self.allow_yield, self.allow_await)
.parse(cursor, interner)?
.into(),
),
if matches!(
cursor.peek(1, interner).or_abrupt()?.kind(),
TokenKind::Keyword((Keyword::Of, false))
) {
init_is_async_of = true;
}

Some(
Expression::new(None, false, self.allow_yield, self.allow_await)
.parse(cursor, interner)?
.into(),
)
}
TokenKind::Punctuator(Punctuator::Semicolon) => None,
_ => Some(
Expand All @@ -174,6 +176,18 @@ where
));
}
(Some(init), TokenKind::Keyword((kw @ (Keyword::In | Keyword::Of), false))) => {
if init_is_async_of
&& init
== ForLoopInitializer::Expression(ast::Expression::Identifier(
Identifier::new(Sym::ASYNC),
))
{
return Err(Error::lex(LexError::Syntax(
"invalid left-hand side expression 'async' of a for-of loop".into(),
init_position,
)));
}

let in_loop = kw == &Keyword::In;
let init = initializer_to_iterable_loop_initializer(
init,
Expand Down

0 comments on commit a6391e3

Please sign in to comment.