Browse Source

Fix invalid syntex errors for allower `let` as variable names (#3743)

pull/3746/head
raskad 9 months ago committed by GitHub
parent
commit
06b1c3394d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 17
      core/parser/src/parser/statement/declaration/lexical.rs
  2. 2
      core/parser/src/parser/statement/declaration/mod.rs
  3. 38
      core/parser/src/parser/statement/iteration/for_statement.rs
  4. 19
      core/parser/src/parser/statement/mod.rs

17
core/parser/src/parser/statement/declaration/lexical.rs

@ -8,7 +8,7 @@
//! [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations //! [spec]: https://tc39.es/ecma262/#sec-let-and-const-declarations
use crate::{ use crate::{
lexer::{Error as LexError, TokenKind}, lexer::{Error as LexError, Token, TokenKind},
parser::{ parser::{
cursor::{Cursor, SemicolonResult}, cursor::{Cursor, SemicolonResult},
expression::Initializer, expression::Initializer,
@ -123,6 +123,21 @@ where
} }
} }
/// Check if the given token is valid after the `let` keyword of a lexical declaration.
pub(crate) fn allowed_token_after_let(token: Option<&Token>) -> bool {
matches!(
token.map(Token::kind),
Some(
TokenKind::IdentifierName(_)
| TokenKind::Keyword((
Keyword::Await | Keyword::Yield | Keyword::Let | Keyword::Async,
_
))
| TokenKind::Punctuator(Punctuator::OpenBlock | Punctuator::OpenBracket),
)
)
}
/// Parses a binding list. /// Parses a binding list.
/// ///
/// It will return an error if a `const` declaration is being parsed and there is no /// It will return an error if a `const` declaration is being parsed and there is no

2
core/parser/src/parser/statement/declaration/mod.rs

@ -20,7 +20,7 @@ pub(in crate::parser) use self::{
class_decl::ClassTail, ClassDeclaration, FunctionDeclaration, HoistableDeclaration, class_decl::ClassTail, ClassDeclaration, FunctionDeclaration, HoistableDeclaration,
}, },
import::ImportDeclaration, import::ImportDeclaration,
lexical::LexicalDeclaration, lexical::{allowed_token_after_let, LexicalDeclaration},
}; };
use crate::{ use crate::{
lexer::TokenKind, lexer::TokenKind,

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

@ -11,8 +11,11 @@ use crate::{
lexer::{Error as LexError, TokenKind}, lexer::{Error as LexError, TokenKind},
parser::{ parser::{
expression::{AssignmentExpression, Expression}, expression::{AssignmentExpression, Expression},
statement::declaration::LexicalDeclaration, statement::{
statement::{variable::VariableDeclarationList, Statement}, declaration::{allowed_token_after_let, LexicalDeclaration},
variable::VariableDeclarationList,
Statement,
},
AllowAwait, AllowReturn, AllowYield, Cursor, OrAbrupt, ParseResult, TokenParser, AllowAwait, AllowReturn, AllowYield, Cursor, OrAbrupt, ParseResult, TokenParser,
}, },
source::ReadChar, source::ReadChar,
@ -20,6 +23,7 @@ use crate::{
}; };
use ast::{ use ast::{
declaration::Binding, declaration::Binding,
expression::Identifier,
operations::{bound_names, var_declared_names}, operations::{bound_names, var_declared_names},
}; };
use boa_ast::{ use boa_ast::{
@ -107,7 +111,7 @@ where
} }
}; };
let init = match cursor.peek(0, interner).or_abrupt()?.kind() { 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);
Some( Some(
@ -116,20 +120,15 @@ where
.into(), .into(),
) )
} }
TokenKind::Keyword((Keyword::Let, _)) => Some('exit: { TokenKind::Keyword((Keyword::Let, false))
if !cursor.strict() { if allowed_token_after_let(cursor.peek(1, interner)?) =>
if let Some(token) = cursor.peek(1, interner)? { {
if token.kind() == &TokenKind::Keyword((Keyword::In, false)) { Some(
cursor.advance(interner);
break 'exit boa_ast::Expression::Identifier(Sym::LET.into()).into();
}
}
}
LexicalDeclaration::new(false, self.allow_yield, self.allow_await, true) LexicalDeclaration::new(false, self.allow_yield, self.allow_await, true)
.parse(cursor, interner)? .parse(cursor, interner)?
.into() .into(),
}), )
}
TokenKind::Keyword((Keyword::Const, _)) => Some( TokenKind::Keyword((Keyword::Const, _)) => Some(
LexicalDeclaration::new(false, self.allow_yield, self.allow_await, true) LexicalDeclaration::new(false, self.allow_yield, self.allow_await, true)
.parse(cursor, interner)? .parse(cursor, interner)?
@ -174,6 +173,15 @@ where
)); ));
} }
(Some(init), TokenKind::Keyword((kw @ (Keyword::In | Keyword::Of), false))) => { (Some(init), TokenKind::Keyword((kw @ (Keyword::In | Keyword::Of), false))) => {
if kw == &Keyword::Of
&& init
== ForLoopInitializer::Expression(ast::Expression::Identifier(
Identifier::new(Sym::LET),
))
{
return Err(Error::general("unexpected token", 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(
init, init,

19
core/parser/src/parser/statement/mod.rs

@ -26,7 +26,7 @@ use self::{
block::BlockStatement, block::BlockStatement,
break_stm::BreakStatement, break_stm::BreakStatement,
continue_stm::ContinueStatement, continue_stm::ContinueStatement,
declaration::{Declaration, ExportDeclaration, ImportDeclaration}, declaration::{allowed_token_after_let, Declaration, ExportDeclaration, ImportDeclaration},
expression::ExpressionStatement, expression::ExpressionStatement,
if_stm::IfStatement, if_stm::IfStatement,
iteration::{DoWhileStatement, ForStatement, WhileStatement}, iteration::{DoWhileStatement, ForStatement, WhileStatement},
@ -412,12 +412,19 @@ where
let _timer = Profiler::global().start_event("StatementListItem", "Parsing"); let _timer = Profiler::global().start_event("StatementListItem", "Parsing");
let tok = cursor.peek(0, interner).or_abrupt()?; let tok = cursor.peek(0, interner).or_abrupt()?;
match *tok.kind() { match tok.kind().clone() {
TokenKind::Keyword( TokenKind::Keyword((Keyword::Function | Keyword::Class | Keyword::Const, _)) => {
(Keyword::Function | Keyword::Class | Keyword::Const, _) | (Keyword::Let, false), Declaration::new(self.allow_yield, self.allow_await)
) => Declaration::new(self.allow_yield, self.allow_await)
.parse(cursor, interner) .parse(cursor, interner)
.map(ast::StatementListItem::from), .map(ast::StatementListItem::from)
}
TokenKind::Keyword((Keyword::Let, false))
if allowed_token_after_let(cursor.peek(1, interner)?) =>
{
Declaration::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)
.map(ast::StatementListItem::from)
}
TokenKind::Keyword((Keyword::Async, false)) => { TokenKind::Keyword((Keyword::Async, false)) => {
let skip_n = if cursor.peek_is_line_terminator(0, interner).or_abrupt()? { let skip_n = if cursor.peek_is_line_terminator(0, interner).or_abrupt()? {
2 2

Loading…
Cancel
Save