Browse Source

Fix parsing of `async` in for-of loops (#3745)

pull/3751/head
raskad 8 months ago committed by GitHub
parent
commit
9e9d71ff91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 17
      core/parser/src/parser/expression/assignment/mod.rs
  2. 26
      core/parser/src/parser/expression/tests.rs
  3. 29
      core/parser/src/parser/statement/iteration/for_statement.rs

17
core/parser/src/parser/expression/assignment/mod.rs

@ -141,15 +141,22 @@ where
1 1
}; };
let peek_1 = cursor.peek(1, interner).or_abrupt()?.kind().clone();
if !cursor if !cursor
.peek_is_line_terminator(skip_n, interner) .peek_is_line_terminator(skip_n, interner)
.or_abrupt()? .or_abrupt()?
&& matches!( && (matches!(peek_1, TokenKind::Punctuator(Punctuator::OpenParen))
cursor.peek(1, interner).or_abrupt()?.kind(), || (matches!(
peek_1,
TokenKind::IdentifierName(_) TokenKind::IdentifierName(_)
| TokenKind::Keyword((Keyword::Yield | Keyword::Await, _)) | TokenKind::Keyword((
| TokenKind::Punctuator(Punctuator::OpenParen) Keyword::Yield | Keyword::Await | Keyword::Of,
) _
))
) && matches!(
cursor.peek(2, interner).or_abrupt()?.kind(),
TokenKind::Punctuator(Punctuator::Arrow)
)))
{ {
return Ok( return Ok(
AsyncArrowFunction::new(self.name, self.allow_in, self.allow_yield) AsyncArrowFunction::new(self.name, self.allow_in, self.allow_yield)

26
core/parser/src/parser/expression/tests.rs

@ -10,7 +10,8 @@ use boa_ast::{
}, },
Call, Identifier, Parenthesized, RegExpLiteral, Call, Identifier, Parenthesized, RegExpLiteral,
}, },
Declaration, Expression, Statement, function::{AsyncArrowFunction, FormalParameter, FormalParameterList},
Declaration, Expression, Script, Statement,
}; };
use boa_interner::{Interner, Sym}; use boa_interner::{Interner, Sym};
use boa_macros::utf16; use boa_macros::utf16;
@ -685,6 +686,29 @@ fn check_logical_expressions() {
check_invalid_script("a || b ?? c"); 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 { macro_rules! check_non_reserved_identifier {
($keyword:literal) => {{ ($keyword:literal) => {{
let interner = &mut Interner::default(); let interner = &mut Interner::default();

29
core/parser/src/parser/statement/iteration/for_statement.rs

@ -111,6 +111,7 @@ where
} }
}; };
let mut init_is_async_of = false;
let init = match cursor.peek(0, interner).or_abrupt()?.kind().clone() { let init = match cursor.peek(0, interner).or_abrupt()?.kind().clone() {
TokenKind::Keyword((Keyword::Var, _)) => { TokenKind::Keyword((Keyword::Var, _)) => {
cursor.advance(interner); cursor.advance(interner);
@ -135,19 +136,18 @@ where
.into(), .into(),
), ),
TokenKind::Keyword((Keyword::Async, false)) if !r#await => { TokenKind::Keyword((Keyword::Async, false)) if !r#await => {
match cursor.peek(1, interner).or_abrupt()?.kind() { if matches!(
TokenKind::Keyword((Keyword::Of, _)) => { cursor.peek(1, interner).or_abrupt()?.kind(),
return Err(Error::lex(LexError::Syntax( TokenKind::Keyword((Keyword::Of, false))
"invalid left-hand side expression 'async' of a for-of loop".into(), ) {
init_position, init_is_async_of = true;
)));
} }
_ => Some(
Some(
Expression::new(None, false, self.allow_yield, self.allow_await) Expression::new(None, false, self.allow_yield, self.allow_await)
.parse(cursor, interner)? .parse(cursor, interner)?
.into(), .into(),
), )
}
} }
TokenKind::Punctuator(Punctuator::Semicolon) => None, TokenKind::Punctuator(Punctuator::Semicolon) => None,
_ => Some( _ => Some(
@ -181,6 +181,17 @@ where
{ {
return Err(Error::general("unexpected token", position)); return Err(Error::general("unexpected token", position));
} }
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 in_loop = kw == &Keyword::In;
let init = initializer_to_iterable_loop_initializer( let init = initializer_to_iterable_loop_initializer(

Loading…
Cancel
Save