Browse Source

Allow unicode escaped characters in identifiers that are keywords (#2021)

This Pull Request changes the following:

- Remove syntax error for unicode escaped characters in keywords from the lexer.
- Adjust the lexer tokens for keywords to indicate if they contain unicode escaped characters.
- Throw syntax errors in parser, when keywords cannot contain unicode escaped characters.
pull/2023/head
raskad 3 years ago
parent
commit
2a63de3d68
  1. 9
      boa_engine/src/syntax/lexer/identifier.rs
  2. 76
      boa_engine/src/syntax/lexer/tests.rs
  3. 15
      boa_engine/src/syntax/lexer/token.rs
  4. 2
      boa_engine/src/syntax/parser/expression/assignment/exponentiation.rs
  5. 4
      boa_engine/src/syntax/parser/expression/assignment/mod.rs
  6. 7
      boa_engine/src/syntax/parser/expression/assignment/yield.rs
  7. 2
      boa_engine/src/syntax/parser/expression/await_expr.rs
  8. 2
      boa_engine/src/syntax/parser/expression/left_hand_side/call.rs
  9. 27
      boa_engine/src/syntax/parser/expression/left_hand_side/member.rs
  10. 10
      boa_engine/src/syntax/parser/expression/mod.rs
  11. 6
      boa_engine/src/syntax/parser/expression/primary/async_function_expression/mod.rs
  12. 6
      boa_engine/src/syntax/parser/expression/primary/async_generator_expression/mod.rs
  13. 2
      boa_engine/src/syntax/parser/expression/primary/class_expression/mod.rs
  14. 2
      boa_engine/src/syntax/parser/expression/primary/function_expression/mod.rs
  15. 20
      boa_engine/src/syntax/parser/expression/primary/mod.rs
  16. 23
      boa_engine/src/syntax/parser/expression/primary/object_initializer/mod.rs
  17. 9
      boa_engine/src/syntax/parser/expression/unary.rs
  18. 2
      boa_engine/src/syntax/parser/statement/break_stm/mod.rs
  19. 2
      boa_engine/src/syntax/parser/statement/continue_stm/mod.rs
  20. 12
      boa_engine/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs
  21. 12
      boa_engine/src/syntax/parser/statement/declaration/hoistable/async_generator_decl/mod.rs
  22. 29
      boa_engine/src/syntax/parser/statement/declaration/hoistable/class_decl/mod.rs
  23. 2
      boa_engine/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs
  24. 6
      boa_engine/src/syntax/parser/statement/declaration/hoistable/generator_decl/mod.rs
  25. 12
      boa_engine/src/syntax/parser/statement/declaration/hoistable/mod.rs
  26. 21
      boa_engine/src/syntax/parser/statement/declaration/lexical.rs
  27. 4
      boa_engine/src/syntax/parser/statement/declaration/mod.rs
  28. 26
      boa_engine/src/syntax/parser/statement/expression/mod.rs
  29. 63
      boa_engine/src/syntax/parser/statement/if_stm/mod.rs
  30. 16
      boa_engine/src/syntax/parser/statement/iteration/do_while_statement.rs
  31. 19
      boa_engine/src/syntax/parser/statement/iteration/for_statement.rs
  32. 2
      boa_engine/src/syntax/parser/statement/iteration/while_statement.rs
  33. 4
      boa_engine/src/syntax/parser/statement/labelled_stm/mod.rs
  34. 38
      boa_engine/src/syntax/parser/statement/mod.rs
  35. 2
      boa_engine/src/syntax/parser/statement/return_stm/mod.rs
  36. 26
      boa_engine/src/syntax/parser/statement/switch/mod.rs
  37. 2
      boa_engine/src/syntax/parser/statement/throw/mod.rs
  38. 2
      boa_engine/src/syntax/parser/statement/try_stm/catch.rs
  39. 2
      boa_engine/src/syntax/parser/statement/try_stm/finally.rs
  40. 26
      boa_engine/src/syntax/parser/statement/try_stm/mod.rs
  41. 2
      boa_engine/src/syntax/parser/statement/variable/mod.rs

9
boa_engine/src/syntax/lexer/identifier.rs

@ -90,13 +90,6 @@ impl<R> Tokenizer<R> for Identifier {
Self::take_identifier_name(cursor, start_pos, self.init)?;
let token_kind = if let Ok(keyword) = identifier_name.parse() {
if contains_escaped_chars {
return Err(Error::Syntax(
"unicode escaped characters are not allowed in keyword".into(),
start_pos,
));
}
if cursor.strict_mode() && keyword == Keyword::With {
return Err(Error::Syntax(
"using 'with' statement not allowed in strict mode".into(),
@ -108,7 +101,7 @@ impl<R> Tokenizer<R> for Identifier {
Keyword::True => TokenKind::BooleanLiteral(true),
Keyword::False => TokenKind::BooleanLiteral(false),
Keyword::Null => TokenKind::NullLiteral,
_ => TokenKind::Keyword(keyword),
_ => TokenKind::Keyword((keyword, contains_escaped_chars)),
}
} else {
if cursor.strict_mode()

76
boa_engine/src/syntax/lexer/tests.rs

@ -36,7 +36,7 @@ fn check_single_line_comment() {
let mut interner = Interner::default();
let expected = [
TokenKind::Keyword(Keyword::Var),
TokenKind::Keyword((Keyword::Var, false)),
TokenKind::LineTerminator,
TokenKind::LineTerminator,
TokenKind::BooleanLiteral(true),
@ -52,7 +52,7 @@ fn check_single_line_comment_with_crlf_ending() {
let mut interner = Interner::default();
let expected = [
TokenKind::Keyword(Keyword::Var),
TokenKind::Keyword((Keyword::Var, false)),
TokenKind::LineTerminator,
TokenKind::LineTerminator,
TokenKind::BooleanLiteral(true),
@ -69,7 +69,7 @@ fn check_multi_line_comment() {
let sym = interner.get_or_intern_static("x");
let expected = [
TokenKind::Keyword(Keyword::Var),
TokenKind::Keyword((Keyword::Var, false)),
TokenKind::LineTerminator,
TokenKind::identifier(sym),
];
@ -251,40 +251,40 @@ fn check_keywords() {
let mut interner = Interner::default();
let expected = [
TokenKind::Keyword(Keyword::Await),
TokenKind::Keyword(Keyword::Break),
TokenKind::Keyword(Keyword::Case),
TokenKind::Keyword(Keyword::Catch),
TokenKind::Keyword(Keyword::Class),
TokenKind::Keyword(Keyword::Const),
TokenKind::Keyword(Keyword::Continue),
TokenKind::Keyword(Keyword::Debugger),
TokenKind::Keyword(Keyword::Default),
TokenKind::Keyword(Keyword::Delete),
TokenKind::Keyword(Keyword::Do),
TokenKind::Keyword(Keyword::Else),
TokenKind::Keyword(Keyword::Export),
TokenKind::Keyword(Keyword::Extends),
TokenKind::Keyword(Keyword::Finally),
TokenKind::Keyword(Keyword::For),
TokenKind::Keyword(Keyword::Function),
TokenKind::Keyword(Keyword::If),
TokenKind::Keyword(Keyword::Import),
TokenKind::Keyword(Keyword::In),
TokenKind::Keyword(Keyword::InstanceOf),
TokenKind::Keyword(Keyword::New),
TokenKind::Keyword(Keyword::Return),
TokenKind::Keyword(Keyword::Super),
TokenKind::Keyword(Keyword::Switch),
TokenKind::Keyword(Keyword::This),
TokenKind::Keyword(Keyword::Throw),
TokenKind::Keyword(Keyword::Try),
TokenKind::Keyword(Keyword::TypeOf),
TokenKind::Keyword(Keyword::Var),
TokenKind::Keyword(Keyword::Void),
TokenKind::Keyword(Keyword::While),
TokenKind::Keyword(Keyword::With),
TokenKind::Keyword(Keyword::Yield),
TokenKind::Keyword((Keyword::Await, false)),
TokenKind::Keyword((Keyword::Break, false)),
TokenKind::Keyword((Keyword::Case, false)),
TokenKind::Keyword((Keyword::Catch, false)),
TokenKind::Keyword((Keyword::Class, false)),
TokenKind::Keyword((Keyword::Const, false)),
TokenKind::Keyword((Keyword::Continue, false)),
TokenKind::Keyword((Keyword::Debugger, false)),
TokenKind::Keyword((Keyword::Default, false)),
TokenKind::Keyword((Keyword::Delete, false)),
TokenKind::Keyword((Keyword::Do, false)),
TokenKind::Keyword((Keyword::Else, false)),
TokenKind::Keyword((Keyword::Export, false)),
TokenKind::Keyword((Keyword::Extends, false)),
TokenKind::Keyword((Keyword::Finally, false)),
TokenKind::Keyword((Keyword::For, false)),
TokenKind::Keyword((Keyword::Function, false)),
TokenKind::Keyword((Keyword::If, false)),
TokenKind::Keyword((Keyword::Import, false)),
TokenKind::Keyword((Keyword::In, false)),
TokenKind::Keyword((Keyword::InstanceOf, false)),
TokenKind::Keyword((Keyword::New, false)),
TokenKind::Keyword((Keyword::Return, false)),
TokenKind::Keyword((Keyword::Super, false)),
TokenKind::Keyword((Keyword::Switch, false)),
TokenKind::Keyword((Keyword::This, false)),
TokenKind::Keyword((Keyword::Throw, false)),
TokenKind::Keyword((Keyword::Try, false)),
TokenKind::Keyword((Keyword::TypeOf, false)),
TokenKind::Keyword((Keyword::Var, false)),
TokenKind::Keyword((Keyword::Void, false)),
TokenKind::Keyword((Keyword::While, false)),
TokenKind::Keyword((Keyword::With, false)),
TokenKind::Keyword((Keyword::Yield, false)),
];
expect_tokens(&mut lexer, &expected, &mut interner);
@ -299,7 +299,7 @@ fn check_variable_definition_tokens() {
let a_sym = interner.get_or_intern_static("a");
let hello_sym = interner.get_or_intern_static("hello");
let expected = [
TokenKind::Keyword(Keyword::Let),
TokenKind::Keyword((Keyword::Let, false)),
TokenKind::identifier(a_sym),
TokenKind::Punctuator(Punctuator::Assign),
TokenKind::string_literal(hello_sym),

15
boa_engine/src/syntax/lexer/token.rs

@ -105,8 +105,8 @@ pub enum TokenKind {
/// A private identifier.
PrivateIdentifier(Sym),
/// A keyword.
Keyword(Keyword),
/// A keyword and a flag if the keyword contains unicode escaped chars.
Keyword((Keyword, bool)),
/// A `null` literal.
NullLiteral,
@ -142,8 +142,8 @@ impl From<bool> for TokenKind {
}
}
impl From<Keyword> for TokenKind {
fn from(kw: Keyword) -> Self {
impl From<(Keyword, bool)> for TokenKind {
fn from(kw: (Keyword, bool)) -> Self {
Self::Keyword(kw)
}
}
@ -176,11 +176,6 @@ impl TokenKind {
Self::Identifier(ident)
}
/// Creates a `Keyword` token kind.
pub fn keyword(keyword: Keyword) -> Self {
Self::Keyword(keyword)
}
/// Creates a `NumericLiteral` token kind.
pub fn numeric_literal<L>(lit: L) -> Self
where
@ -229,7 +224,7 @@ impl TokenKind {
Self::EOF => "end of file".to_owned(),
Self::Identifier(ident) => interner.resolve_expect(ident).to_owned(),
Self::PrivateIdentifier(ident) => format!("#{}", interner.resolve_expect(ident)),
Self::Keyword(word) => word.to_string(),
Self::Keyword((word, _)) => word.to_string(),
Self::NullLiteral => "null".to_owned(),
Self::NumericLiteral(Numeric::Rational(num)) => num.to_string(),
Self::NumericLiteral(Numeric::Integer(num)) => num.to_string(),

2
boa_engine/src/syntax/parser/expression/assignment/exponentiation.rs

@ -70,7 +70,7 @@ where
Ok(if let Some(tok) = cursor.peek(0, interner)? {
matches!(
tok.kind(),
TokenKind::Keyword(Keyword::Delete | Keyword::Void | Keyword::TypeOf)
TokenKind::Keyword((Keyword::Delete | Keyword::Void | Keyword::TypeOf, _))
| TokenKind::Punctuator(
Punctuator::Add | Punctuator::Sub | Punctuator::Not | Punctuator::Neg
)

4
boa_engine/src/syntax/parser/expression/assignment/mod.rs

@ -97,12 +97,12 @@ where
.kind()
{
// [+Yield]YieldExpression[?In, ?Await]
TokenKind::Keyword(Keyword::Yield) if self.allow_yield.0 => {
TokenKind::Keyword((Keyword::Yield, _)) if self.allow_yield.0 => {
return YieldExpression::new(self.allow_in, self.allow_await)
.parse(cursor, interner)
}
// ArrowFunction[?In, ?Yield, ?Await] -> ArrowParameters[?Yield, ?Await] -> BindingIdentifier[?Yield, ?Await]
TokenKind::Identifier(_) | TokenKind::Keyword(Keyword::Yield | Keyword::Await) => {
TokenKind::Identifier(_) | TokenKind::Keyword((Keyword::Yield | Keyword::Await, _)) => {
if let Ok(tok) =
cursor.peek_expect_no_lineterminator(1, "assignment expression", interner)
{

7
boa_engine/src/syntax/parser/expression/assignment/yield.rs

@ -58,7 +58,7 @@ where
let _timer = Profiler::global().start_event("YieldExpression", "Parsing");
cursor.expect(
TokenKind::Keyword(Keyword::Yield),
TokenKind::Keyword((Keyword::Yield, false)),
"yield expression",
interner,
)?;
@ -87,7 +87,7 @@ where
| Punctuator::OpenBlock
| Punctuator::Div,
)
| TokenKind::Keyword(
| TokenKind::Keyword((
Keyword::Yield
| Keyword::Await
| Keyword::Delete
@ -98,7 +98,8 @@ where
| Keyword::Function
| Keyword::Class
| Keyword::Async,
)
_,
))
| TokenKind::BooleanLiteral(_)
| TokenKind::NullLiteral
| TokenKind::StringLiteral(_)

2
boa_engine/src/syntax/parser/expression/await_expr.rs

@ -53,7 +53,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
cursor.expect(
TokenKind::Keyword(Keyword::Await),
TokenKind::Keyword((Keyword::Await, false)),
"Await expression parsing",
interner,
)?;

2
boa_engine/src/syntax/parser/expression/left_hand_side/call.rs

@ -94,7 +94,7 @@ where
TokenKind::Identifier(name) => {
lhs = GetConstField::new(lhs, *name).into();
}
TokenKind::Keyword(kw) => {
TokenKind::Keyword((kw, _)) => {
lhs = GetConstField::new(lhs, kw.to_sym(interner)).into();
}
_ => {

27
boa_engine/src/syntax/parser/expression/left_hand_side/member.rs

@ -64,27 +64,32 @@ where
fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult {
let _timer = Profiler::global().start_event("MemberExpression", "Parsing");
let mut lhs = if cursor
.peek(0, interner)?
.ok_or(ParseError::AbruptEnd)?
.kind()
== &TokenKind::Keyword(Keyword::New)
{
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
let mut lhs = match token.kind() {
TokenKind::Keyword((Keyword::New, true)) => {
return Err(ParseError::general(
"keyword must not contain escaped characters",
token.span().start(),
));
}
TokenKind::Keyword((Keyword::New, false)) => {
let _next = cursor.next(interner).expect("new keyword disappeared");
let lhs = self.parse(cursor, interner)?;
let args = match cursor.peek(0, interner)? {
Some(next) if next.kind() == &TokenKind::Punctuator(Punctuator::OpenParen) => {
Arguments::new(self.allow_yield, self.allow_await).parse(cursor, interner)?
Arguments::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)?
}
_ => Box::new([]),
};
let call_node = Call::new(lhs, args);
Node::from(New::from(call_node))
} else {
PrimaryExpression::new(self.name, self.allow_yield, self.allow_await)
.parse(cursor, interner)?
}
_ => PrimaryExpression::new(self.name, self.allow_yield, self.allow_await)
.parse(cursor, interner)?,
};
while let Some(tok) = cursor.peek(0, interner)? {
match tok.kind() {
TokenKind::Punctuator(Punctuator::Dot) => {
@ -96,7 +101,7 @@ where
match token.kind() {
TokenKind::Identifier(name) => lhs = GetConstField::new(lhs, *name).into(),
TokenKind::Keyword(kw) => {
TokenKind::Keyword((kw, _)) => {
lhs = GetConstField::new(lhs, kw.to_sym(interner)).into();
}
TokenKind::BooleanLiteral(bool) => {

10
boa_engine/src/syntax/parser/expression/mod.rs

@ -98,7 +98,7 @@ macro_rules! expression { ($name:ident, $lower:ident, [$( $op:path ),*], [$( $lo
$lower::new($( self.$low_param ),*).parse(cursor, interner)?
).into();
}
TokenKind::Keyword(op) if $( op == $op )||* => {
TokenKind::Keyword((op, false)) if $( op == $op )||* => {
let _next = cursor.next(interner).expect("token disappeared");
lhs = BinOp::new(
op.as_binop().expect("Could not get binary operation."),
@ -540,7 +540,13 @@ where
)
.into();
}
TokenKind::Keyword(op)
TokenKind::Keyword((Keyword::InstanceOf | Keyword::In, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
tok.span().start(),
));
}
TokenKind::Keyword((op, false))
if op == Keyword::InstanceOf
|| (op == Keyword::In && self.allow_in == AllowIn(true)) =>
{

6
boa_engine/src/syntax/parser/expression/primary/async_function_expression/mod.rs

@ -55,7 +55,11 @@ where
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("AsyncFunctionExpression", "Parsing");
cursor.peek_expect_no_lineterminator(0, "async function expression", interner)?;
cursor.expect(Keyword::Function, "async function expression", interner)?;
cursor.expect(
(Keyword::Function, false),
"async function expression",
interner,
)?;
let name = match cursor
.peek(0, interner)?

6
boa_engine/src/syntax/parser/expression/primary/async_generator_expression/mod.rs

@ -59,7 +59,11 @@ where
let _timer = Profiler::global().start_event("AsyncGeneratorExpression", "Parsing");
cursor.peek_expect_no_lineterminator(0, "async generator expression", interner)?;
cursor.expect(Keyword::Function, "async generator expression", interner)?;
cursor.expect(
(Keyword::Function, false),
"async generator expression",
interner,
)?;
cursor.expect(
TokenKind::Punctuator(Punctuator::Mul),
"async generator expression",

2
boa_engine/src/syntax/parser/expression/primary/class_expression/mod.rs

@ -56,7 +56,7 @@ where
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
let name = match token.kind() {
TokenKind::Identifier(_) | TokenKind::Keyword(Keyword::Yield | Keyword::Await) => {
TokenKind::Identifier(_) | TokenKind::Keyword((Keyword::Yield | Keyword::Await, _)) => {
BindingIdentifier::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)?
}

2
boa_engine/src/syntax/parser/expression/primary/function_expression/mod.rs

@ -64,7 +64,7 @@ where
.ok_or(ParseError::AbruptEnd)?
.kind()
{
TokenKind::Identifier(_) | TokenKind::Keyword(Keyword::Yield | Keyword::Await) => {
TokenKind::Identifier(_) | TokenKind::Keyword((Keyword::Yield | Keyword::Await, _)) => {
Some(BindingIdentifier::new(false, false).parse(cursor, interner)?)
}
_ => self.name,

20
boa_engine/src/syntax/parser/expression/primary/mod.rs

@ -88,8 +88,12 @@ where
let tok = cursor.next(interner)?.ok_or(ParseError::AbruptEnd)?;
match tok.kind() {
TokenKind::Keyword(Keyword::This) => Ok(Node::This),
TokenKind::Keyword(Keyword::Function) => {
TokenKind::Keyword((Keyword::This | Keyword::Async, true)) => Err(ParseError::general(
"Keyword must not contain escaped characters",
tok.span().start(),
)),
TokenKind::Keyword((Keyword::This, false)) => Ok(Node::This),
TokenKind::Keyword((Keyword::Function, _)) => {
let next_token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
if next_token.kind() == &TokenKind::Punctuator(Punctuator::Mul) {
GeneratorExpression::new(self.name)
@ -101,10 +105,10 @@ where
.map(Node::from)
}
}
TokenKind::Keyword(Keyword::Class) => {
TokenKind::Keyword((Keyword::Class, _)) => {
ClassExpression::new(self.name, false, false).parse(cursor, interner)
}
TokenKind::Keyword(Keyword::Async) => {
TokenKind::Keyword((Keyword::Async, false)) => {
let mul_peek = cursor.peek(1, interner)?.ok_or(ParseError::AbruptEnd)?;
if mul_peek.kind() == &TokenKind::Punctuator(Punctuator::Mul) {
AsyncGeneratorExpression::new(self.name)
@ -138,14 +142,14 @@ where
TokenKind::BooleanLiteral(boolean) => Ok(Const::from(*boolean).into()),
TokenKind::NullLiteral => Ok(Const::Null.into()),
TokenKind::Identifier(ident) => Ok(Identifier::new(*ident).into()),
TokenKind::Keyword(Keyword::Yield) if self.allow_yield.0 => {
TokenKind::Keyword((Keyword::Yield, _)) if self.allow_yield.0 => {
// Early Error: It is a Syntax Error if this production has a [Yield] parameter and StringValue of Identifier is "yield".
Err(ParseError::general(
"Unexpected identifier",
tok.span().start(),
))
}
TokenKind::Keyword(Keyword::Yield) if !self.allow_yield.0 => {
TokenKind::Keyword((Keyword::Yield, _)) if !self.allow_yield.0 => {
if cursor.strict_mode() {
return Err(ParseError::general(
"Unexpected strict mode reserved word",
@ -154,14 +158,14 @@ where
}
Ok(Identifier::new(Sym::YIELD).into())
}
TokenKind::Keyword(Keyword::Await) if self.allow_await.0 => {
TokenKind::Keyword((Keyword::Await, _)) if self.allow_await.0 => {
// Early Error: It is a Syntax Error if this production has an [Await] parameter and StringValue of Identifier is "await".
Err(ParseError::general(
"Unexpected identifier",
tok.span().start(),
))
}
TokenKind::Keyword(Keyword::Await) if !self.allow_await.0 => {
TokenKind::Keyword((Keyword::Await, _)) if !self.allow_await.0 => {
if cursor.strict_mode() {
return Err(ParseError::general(
"Unexpected strict mode reserved word",

23
boa_engine/src/syntax/parser/expression/primary/object_initializer/mod.rs

@ -161,14 +161,14 @@ where
)));
}
TokenKind::Identifier(ident) => Identifier::new(*ident),
TokenKind::Keyword(Keyword::Yield) if self.allow_yield.0 => {
TokenKind::Keyword((Keyword::Yield, _)) if self.allow_yield.0 => {
// Early Error: It is a Syntax Error if this production has a [Yield] parameter and StringValue of Identifier is "yield".
return Err(ParseError::general(
"Unexpected identifier",
token.span().start(),
));
}
TokenKind::Keyword(Keyword::Yield) if !self.allow_yield.0 => {
TokenKind::Keyword((Keyword::Yield, _)) if !self.allow_yield.0 => {
if cursor.strict_mode() {
// Early Error: It is a Syntax Error if the code matched by this production is contained in strict mode code.
return Err(ParseError::general(
@ -178,14 +178,14 @@ where
}
Identifier::new(Sym::YIELD)
}
TokenKind::Keyword(Keyword::Await) if self.allow_await.0 => {
TokenKind::Keyword((Keyword::Await, _)) if self.allow_await.0 => {
// Early Error: It is a Syntax Error if this production has an [Await] parameter and StringValue of Identifier is "await".
return Err(ParseError::general(
"Unexpected identifier",
token.span().start(),
));
}
TokenKind::Keyword(Keyword::Await) if !self.allow_await.0 => {
TokenKind::Keyword((Keyword::Await, _)) if !self.allow_await.0 => {
if cursor.strict_mode() {
// Early Error: It is a Syntax Error if the code matched by this production is contained in strict mode code.
return Err(ParseError::general(
@ -215,7 +215,16 @@ where
}
//Async [AsyncMethod, AsyncGeneratorMethod] object methods
if cursor.next_if(Keyword::Async, interner)?.is_some() {
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match token.kind() {
TokenKind::Keyword((Keyword::Async, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
token.span().start(),
));
}
TokenKind::Keyword((Keyword::Async, false)) => {
cursor.next(interner)?.expect("token disappeared");
cursor.peek_expect_no_lineterminator(0, "Async object methods", interner)?;
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
@ -235,6 +244,8 @@ where
property_name,
));
}
_ => {}
}
if cursor
.peek(0, interner)?
@ -465,7 +476,7 @@ where
Numeric::Integer(num) => Node::Const(Const::from(*num)).into(),
Numeric::BigInt(num) => Node::Const(Const::from(num.clone())).into(),
},
TokenKind::Keyword(word) => {
TokenKind::Keyword((word, _)) => {
Node::Const(Const::from(interner.get_or_intern_static(word.as_str()))).into()
}
TokenKind::NullLiteral => Node::Const(Const::from(Sym::NULL)).into(),

9
boa_engine/src/syntax/parser/expression/unary.rs

@ -66,7 +66,10 @@ where
let tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
let token_start = tok.span().start();
match tok.kind() {
TokenKind::Keyword(Keyword::Delete) => {
TokenKind::Keyword((Keyword::Delete | Keyword::Void | Keyword::TypeOf, true)) => Err(
ParseError::general("Keyword must not contain escaped characters", token_start),
),
TokenKind::Keyword((Keyword::Delete, false)) => {
cursor.next(interner)?.expect("Delete keyword vanished");
let position = cursor
.peek(0, interner)?
@ -93,11 +96,11 @@ where
Ok(node::UnaryOp::new(UnaryOp::Delete, val).into())
}
TokenKind::Keyword(Keyword::Void) => {
TokenKind::Keyword((Keyword::Void, false)) => {
cursor.next(interner)?.expect("Void keyword vanished"); // Consume the token.
Ok(node::UnaryOp::new(UnaryOp::Void, self.parse(cursor, interner)?).into())
}
TokenKind::Keyword(Keyword::TypeOf) => {
TokenKind::Keyword((Keyword::TypeOf, false)) => {
cursor.next(interner)?.expect("TypeOf keyword vanished"); // Consume the token.
Ok(node::UnaryOp::new(UnaryOp::TypeOf, self.parse(cursor, interner)?).into())
}

2
boa_engine/src/syntax/parser/statement/break_stm/mod.rs

@ -63,7 +63,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("BreakStatement", "Parsing");
cursor.expect(Keyword::Break, "break statement", interner)?;
cursor.expect((Keyword::Break, false), "break statement", interner)?;
let label = if let SemicolonResult::Found(tok) = cursor.peek_semicolon(interner)? {
match tok {

2
boa_engine/src/syntax/parser/statement/continue_stm/mod.rs

@ -63,7 +63,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("ContinueStatement", "Parsing");
cursor.expect(Keyword::Continue, "continue statement", interner)?;
cursor.expect((Keyword::Continue, false), "continue statement", interner)?;
let label = if let SemicolonResult::Found(tok) = cursor.peek_semicolon(interner)? {
match tok {

12
boa_engine/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs

@ -80,9 +80,17 @@ where
cursor: &mut Cursor<R>,
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
cursor.expect(Keyword::Async, "async function declaration", interner)?;
cursor.expect(
(Keyword::Async, false),
"async function declaration",
interner,
)?;
cursor.peek_expect_no_lineterminator(0, "async function declaration", interner)?;
cursor.expect(Keyword::Function, "async function declaration", interner)?;
cursor.expect(
(Keyword::Function, false),
"async function declaration",
interner,
)?;
let result = parse_callable_declaration(&self, cursor, interner)?;

12
boa_engine/src/syntax/parser/statement/declaration/hoistable/async_generator_decl/mod.rs

@ -98,9 +98,17 @@ where
cursor: &mut Cursor<R>,
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
cursor.expect(Keyword::Async, "async generator declaration", interner)?;
cursor.expect(
(Keyword::Async, false),
"async generator declaration",
interner,
)?;
cursor.peek_expect_no_lineterminator(0, "async generator declaration", interner)?;
cursor.expect(Keyword::Function, "async generator declaration", interner)?;
cursor.expect(
(Keyword::Function, false),
"async generator declaration",
interner,
)?;
cursor.expect(Punctuator::Mul, "async generator declaration", interner)?;
let result = parse_callable_declaration(&self, cursor, interner)?;

29
boa_engine/src/syntax/parser/statement/declaration/hoistable/class_decl/mod.rs

@ -69,13 +69,13 @@ where
cursor: &mut Cursor<R>,
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
cursor.expect(Keyword::Class, "class declaration", interner)?;
cursor.expect((Keyword::Class, false), "class declaration", interner)?;
let strict = cursor.strict_mode();
cursor.set_strict_mode(true);
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
let name = match token.kind() {
TokenKind::Identifier(_) | TokenKind::Keyword(Keyword::Yield | Keyword::Await) => {
TokenKind::Identifier(_) | TokenKind::Keyword((Keyword::Yield | Keyword::Await, _)) => {
BindingIdentifier::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)?
}
@ -136,12 +136,17 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
let super_ref = if token.kind() == &TokenKind::Keyword(Keyword::Extends) {
Some(Box::new(
let super_ref = match token.kind() {
TokenKind::Keyword((Keyword::Extends, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
token.span().start(),
));
}
TokenKind::Keyword((Keyword::Extends, false)) => Some(Box::new(
ClassHeritage::new(self.allow_yield, self.allow_await).parse(cursor, interner)?,
))
} else {
None
)),
_ => None,
};
cursor.expect(Punctuator::OpenBlock, "class tail", interner)?;
@ -207,7 +212,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
cursor.expect(
TokenKind::Keyword(Keyword::Extends),
TokenKind::Keyword((Keyword::Extends, false)),
"class heritage",
interner,
)?;
@ -592,7 +597,13 @@ where
ClassElementNode::MethodDefinition(property_name, method)
}
}
TokenKind::Keyword(Keyword::Async) => {
TokenKind::Keyword((Keyword::Async, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
token.span().start(),
));
}
TokenKind::Keyword((Keyword::Async, false)) => {
cursor.next(interner).expect("token disappeared");
cursor.peek_expect_no_lineterminator(0, "Async object methods", interner)?;
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;

2
boa_engine/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs

@ -85,7 +85,7 @@ where
cursor: &mut Cursor<R>,
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
cursor.expect(Keyword::Function, "function declaration", interner)?;
cursor.expect((Keyword::Function, false), "function declaration", interner)?;
let result = parse_callable_declaration(&self, cursor, interner)?;

6
boa_engine/src/syntax/parser/statement/declaration/hoistable/generator_decl/mod.rs

@ -80,7 +80,11 @@ where
cursor: &mut Cursor<R>,
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
cursor.expect(Keyword::Function, "generator declaration", interner)?;
cursor.expect(
(Keyword::Function, false),
"generator declaration",
interner,
)?;
cursor.expect(Punctuator::Mul, "generator declaration", interner)?;
let result = parse_callable_declaration(&self, cursor, interner)?;

12
boa_engine/src/syntax/parser/statement/declaration/hoistable/mod.rs

@ -75,7 +75,13 @@ where
let tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match tok.kind() {
TokenKind::Keyword(Keyword::Function) => {
TokenKind::Keyword((Keyword::Function | Keyword::Async | Keyword::Class, true)) => {
Err(ParseError::general(
"Keyword must not contain escaped characters",
tok.span().start(),
))
}
TokenKind::Keyword((Keyword::Function, false)) => {
let next_token = cursor.peek(1, interner)?.ok_or(ParseError::AbruptEnd)?;
if let TokenKind::Punctuator(Punctuator::Mul) = next_token.kind() {
GeneratorDeclaration::new(self.allow_yield, self.allow_await, self.is_default)
@ -87,7 +93,7 @@ where
.map(Node::from)
}
}
TokenKind::Keyword(Keyword::Async) => {
TokenKind::Keyword((Keyword::Async, false)) => {
let next_token = cursor.peek(2, interner)?.ok_or(ParseError::AbruptEnd)?;
if let TokenKind::Punctuator(Punctuator::Mul) = next_token.kind() {
AsyncGeneratorDeclaration::new(
@ -103,7 +109,7 @@ where
.map(Node::from)
}
}
TokenKind::Keyword(Keyword::Class) => {
TokenKind::Keyword((Keyword::Class, false)) => {
ClassDeclaration::new(false, false, self.is_default)
.parse(cursor, interner)
.map(Node::from)

21
boa_engine/src/syntax/parser/statement/declaration/lexical.rs

@ -74,7 +74,11 @@ where
let tok = cursor.next(interner)?.ok_or(ParseError::AbruptEnd)?;
match tok.kind() {
TokenKind::Keyword(Keyword::Const) => BindingList::new(
TokenKind::Keyword((Keyword::Const | Keyword::Let, true)) => Err(ParseError::general(
"Keyword must not contain escaped characters",
tok.span().start(),
)),
TokenKind::Keyword((Keyword::Const, false)) => BindingList::new(
self.allow_in,
self.allow_yield,
self.allow_await,
@ -82,7 +86,7 @@ where
self.const_init_required,
)
.parse(cursor, interner),
TokenKind::Keyword(Keyword::Let) => BindingList::new(
TokenKind::Keyword((Keyword::Let, false)) => BindingList::new(
self.allow_in,
self.allow_yield,
self.allow_await,
@ -182,8 +186,17 @@ where
match cursor.peek_semicolon(interner)? {
SemicolonResult::Found(_) => break,
SemicolonResult::NotFound(tk)
if tk.kind() == &TokenKind::Keyword(Keyword::Of)
|| tk.kind() == &TokenKind::Keyword(Keyword::In) =>
if tk.kind() == &TokenKind::Keyword((Keyword::Of, true))
|| tk.kind() == &TokenKind::Keyword((Keyword::In, true)) =>
{
return Err(ParseError::general(
"Keyword must not contain escaped characters",
tk.span().start(),
));
}
SemicolonResult::NotFound(tk)
if tk.kind() == &TokenKind::Keyword((Keyword::Of, false))
|| tk.kind() == &TokenKind::Keyword((Keyword::In, false)) =>
{
break
}

4
boa_engine/src/syntax/parser/statement/declaration/mod.rs

@ -67,11 +67,11 @@ where
let tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match tok.kind() {
TokenKind::Keyword(Keyword::Function | Keyword::Async | Keyword::Class) => {
TokenKind::Keyword((Keyword::Function | Keyword::Async | Keyword::Class, _)) => {
HoistableDeclaration::new(self.allow_yield, self.allow_await, false)
.parse(cursor, interner)
}
TokenKind::Keyword(Keyword::Const | Keyword::Let) => LexicalDeclaration::new(
TokenKind::Keyword((Keyword::Const | Keyword::Let, _)) => LexicalDeclaration::new(
true,
self.allow_yield,
self.allow_await,

26
boa_engine/src/syntax/parser/statement/expression/mod.rs

@ -47,22 +47,40 @@ where
let next_token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match next_token.kind() {
TokenKind::Keyword(Keyword::Function | Keyword::Class) => {
TokenKind::Keyword((
Keyword::Function | Keyword::Class | Keyword::Async | Keyword::Let,
true,
)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
next_token.span().start(),
));
}
TokenKind::Keyword((Keyword::Function | Keyword::Class, false)) => {
return Err(ParseError::general(
"expected statement",
next_token.span().start(),
));
}
TokenKind::Keyword(Keyword::Async) => {
TokenKind::Keyword((Keyword::Async, false)) => {
let next_token = cursor.peek(1, interner)?.ok_or(ParseError::AbruptEnd)?;
if next_token.kind() == &TokenKind::Keyword(Keyword::Function) {
match next_token.kind() {
TokenKind::Keyword((Keyword::Function, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
next_token.span().start(),
));
}
TokenKind::Keyword((Keyword::Function, false)) => {
return Err(ParseError::general(
"expected statement",
next_token.span().start(),
));
}
_ => {}
}
}
TokenKind::Keyword(Keyword::Let) => {
TokenKind::Keyword((Keyword::Let, false)) => {
let next_token = cursor.peek(1, interner)?.ok_or(ParseError::AbruptEnd)?;
if next_token.kind() == &TokenKind::Punctuator(Punctuator::OpenBracket) {
return Err(ParseError::general(

63
boa_engine/src/syntax/parser/statement/if_stm/mod.rs

@ -60,7 +60,7 @@ where
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("IfStatement", "Parsing");
cursor.expect(Keyword::If, "if statement", interner)?;
cursor.expect((Keyword::If, false), "if statement", interner)?;
cursor.expect(Punctuator::OpenParen, "if statement", interner)?;
let condition = Expression::new(None, true, self.allow_yield, self.allow_await)
@ -71,19 +71,17 @@ where
.span()
.end();
let then_node = if !cursor.strict_mode()
&& cursor
.peek(0, interner)?
.ok_or(ParseError::AbruptEnd)?
.kind()
== &TokenKind::Keyword(Keyword::Function)
{
let strict = cursor.strict_mode();
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
let then_node = match token.kind() {
TokenKind::Keyword((Keyword::Function, _)) if !strict => {
// FunctionDeclarations in IfStatement Statement Clauses
// https://tc39.es/ecma262/#sec-functiondeclarations-in-ifstatement-statement-clauses
FunctionDeclaration::new(self.allow_yield, self.allow_await, false)
.parse(cursor, interner)?
.into()
} else {
}
_ => {
let node = Statement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)?;
@ -93,22 +91,24 @@ where
}
node
}
};
let else_node = if cursor.next_if(Keyword::Else, interner)?.is_some() {
let position = cursor
.peek(0, interner)?
.ok_or(ParseError::AbruptEnd)?
.span()
.start();
if !cursor.strict_mode()
&& cursor
.peek(0, interner)?
.ok_or(ParseError::AbruptEnd)?
.kind()
== &TokenKind::Keyword(Keyword::Function)
{
let else_node = if let Some(token) = cursor.peek(0, interner)? {
match token.kind() {
TokenKind::Keyword((Keyword::Else, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
token.span().start(),
));
}
TokenKind::Keyword((Keyword::Else, false)) => {
cursor.next(interner)?.expect("token disappeared");
let strict = cursor.strict_mode();
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match token.kind() {
TokenKind::Keyword((Keyword::Function, _)) if !strict => {
// FunctionDeclarations in IfStatement Statement Clauses
// https://tc39.es/ecma262/#sec-functiondeclarations-in-ifstatement-statement-clauses
Some(
@ -116,17 +116,28 @@ where
.parse(cursor, interner)?
.into(),
)
} else {
let node = Statement::new(self.allow_yield, self.allow_await, self.allow_return)
}
_ => {
let node = Statement::new(
self.allow_yield,
self.allow_await,
self.allow_return,
)
.parse(cursor, interner)?;
// Early Error: It is a Syntax Error if IsLabelledFunction(the second Statement) is true.
if let Node::FunctionDecl(_) = node {
return Err(ParseError::wrong_function_declaration_non_strict(position));
return Err(ParseError::wrong_function_declaration_non_strict(
position,
));
}
Some(node)
}
}
}
_ => None,
}
} else {
None
};

16
boa_engine/src/syntax/parser/statement/iteration/do_while_statement.rs

@ -68,7 +68,7 @@ where
let _timer = Profiler::global().start_event("DoWhileStatement", "Parsing");
let position = cursor
.expect(Keyword::Do, "do while statement", interner)?
.expect((Keyword::Do, false), "do while statement", interner)?
.span()
.end();
@ -81,8 +81,15 @@ where
}
let next_token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
if next_token.kind() != &TokenKind::Keyword(Keyword::While) {
match next_token.kind() {
TokenKind::Keyword((Keyword::While, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
next_token.span().start(),
));
}
TokenKind::Keyword((Keyword::While, false)) => {}
_ => {
return Err(ParseError::expected(
["while".to_owned()],
next_token.to_string(interner),
@ -90,8 +97,9 @@ where
"do while statement",
));
}
}
cursor.expect(Keyword::While, "do while statement", interner)?;
cursor.expect((Keyword::While, false), "do while statement", interner)?;
cursor.expect(Punctuator::OpenParen, "do while statement", interner)?;

19
boa_engine/src/syntax/parser/statement/iteration/for_statement.rs

@ -77,7 +77,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("ForStatement", "Parsing");
cursor.expect(Keyword::For, "for statement", interner)?;
cursor.expect((Keyword::For, false), "for statement", interner)?;
let init_position = cursor
.expect(Punctuator::OpenParen, "for statement", interner)?
.span()
@ -88,7 +88,7 @@ where
.ok_or(ParseError::AbruptEnd)?
.kind()
{
TokenKind::Keyword(Keyword::Var) => {
TokenKind::Keyword((Keyword::Var, _)) => {
let _next = cursor.next(interner)?;
Some(
VariableDeclarationList::new(false, self.allow_yield, self.allow_await)
@ -96,7 +96,7 @@ where
.map(Node::from)?,
)
}
TokenKind::Keyword(Keyword::Let | Keyword::Const) => Some(
TokenKind::Keyword((Keyword::Let | Keyword::Const, _)) => Some(
Declaration::new(self.allow_yield, self.allow_await, false)
.parse(cursor, interner)?,
),
@ -107,8 +107,15 @@ where
),
};
match (init.as_ref(), cursor.peek(0, interner)?) {
(Some(init), Some(tok)) if tok.kind() == &TokenKind::Keyword(Keyword::In) => {
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match (init.as_ref(), token.kind()) {
(Some(_), TokenKind::Keyword((Keyword::In | Keyword::Of, true))) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
token.span().start(),
));
}
(Some(init), TokenKind::Keyword((Keyword::In, false))) => {
let init = node_to_iterable_loop_initializer(init, init_position)?;
let _next = cursor.next(interner)?;
@ -130,7 +137,7 @@ where
return Ok(ForInLoop::new(init, expr, body).into());
}
(Some(init), Some(tok)) if tok.kind() == &TokenKind::Keyword(Keyword::Of) => {
(Some(init), TokenKind::Keyword((Keyword::Of, false))) => {
let init = node_to_iterable_loop_initializer(init, init_position)?;
let _next = cursor.next(interner)?;

2
boa_engine/src/syntax/parser/statement/iteration/while_statement.rs

@ -56,7 +56,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("WhileStatement", "Parsing");
cursor.expect(Keyword::While, "while statement", interner)?;
cursor.expect((Keyword::While, false), "while statement", interner)?;
cursor.expect(Punctuator::OpenParen, "while statement", interner)?;

4
boa_engine/src/syntax/parser/statement/labelled_stm/mod.rs

@ -69,13 +69,13 @@ where
// Early Error: It is a Syntax Error if any strict mode source code matches this rule.
// https://tc39.es/ecma262/#sec-labelled-statements-static-semantics-early-errors
// https://tc39.es/ecma262/#sec-labelled-function-declarations
TokenKind::Keyword(Keyword::Function) if strict => {
TokenKind::Keyword((Keyword::Function, _)) if strict => {
return Err(ParseError::general(
"In strict mode code, functions can only be declared at top level or inside a block.",
next_token.span().start()
))
}
TokenKind::Keyword(Keyword::Function) => {
TokenKind::Keyword((Keyword::Function, _)) => {
FunctionDeclaration::new(self.allow_yield, self.allow_await, false)
.parse(cursor, interner)?
.into()

38
boa_engine/src/syntax/parser/statement/mod.rs

@ -126,35 +126,35 @@ where
let tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match tok.kind() {
TokenKind::Keyword(Keyword::Await) => AwaitExpression::new(self.allow_yield)
TokenKind::Keyword((Keyword::Await, _)) => AwaitExpression::new(self.allow_yield)
.parse(cursor, interner)
.map(Node::from),
TokenKind::Keyword(Keyword::If) => {
TokenKind::Keyword((Keyword::If, _)) => {
IfStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Var) => {
TokenKind::Keyword((Keyword::Var, _)) => {
VariableStatement::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)
.map(Node::from)
}
TokenKind::Keyword(Keyword::While) => {
TokenKind::Keyword((Keyword::While, _)) => {
WhileStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Do) => {
TokenKind::Keyword((Keyword::Do, _)) => {
DoWhileStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)
.map(Node::from)
}
TokenKind::Keyword(Keyword::For) => {
TokenKind::Keyword((Keyword::For, _)) => {
ForStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Return) => {
TokenKind::Keyword((Keyword::Return, _)) => {
if self.allow_return.0 {
ReturnStatement::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)
@ -167,27 +167,27 @@ where
))
}
}
TokenKind::Keyword(Keyword::Break) => {
TokenKind::Keyword((Keyword::Break, _)) => {
BreakStatement::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Continue) => {
TokenKind::Keyword((Keyword::Continue, _)) => {
ContinueStatement::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Try) => {
TokenKind::Keyword((Keyword::Try, _)) => {
TryStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Throw) => {
TokenKind::Keyword((Keyword::Throw, _)) => {
ThrowStatement::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Switch) => {
TokenKind::Keyword((Keyword::Switch, _)) => {
SwitchStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)
.map(Node::from)
@ -471,7 +471,7 @@ where
let tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match *tok.kind() {
TokenKind::Keyword(Keyword::Function | Keyword::Async | Keyword::Class) => {
TokenKind::Keyword((Keyword::Function | Keyword::Async | Keyword::Class, _)) => {
if strict_mode && self.in_block {
return Err(ParseError::lex(LexError::Syntax(
"Function declaration in blocks not allowed in strict mode".into(),
@ -480,7 +480,7 @@ where
}
Declaration::new(self.allow_yield, self.allow_await, true).parse(cursor, interner)
}
TokenKind::Keyword(Keyword::Const | Keyword::Let) => {
TokenKind::Keyword((Keyword::Const | Keyword::Let, _)) => {
Declaration::new(self.allow_yield, self.allow_await, true).parse(cursor, interner)
}
_ => Statement::new(self.allow_yield, self.allow_await, self.allow_return)
@ -555,14 +555,14 @@ where
)))
}
TokenKind::Identifier(ref s) => Ok(*s),
TokenKind::Keyword(Keyword::Yield) if self.allow_yield.0 => {
TokenKind::Keyword((Keyword::Yield, _)) if self.allow_yield.0 => {
// Early Error: It is a Syntax Error if this production has a [Yield] parameter and StringValue of Identifier is "yield".
Err(ParseError::general(
"Unexpected identifier",
next_token.span().start(),
))
}
TokenKind::Keyword(Keyword::Yield) if !self.allow_yield.0 => {
TokenKind::Keyword((Keyword::Yield, _)) if !self.allow_yield.0 => {
if cursor.strict_mode() {
Err(ParseError::general(
"yield keyword in binding identifier not allowed in strict mode",
@ -572,15 +572,15 @@ where
Ok(Sym::YIELD)
}
}
TokenKind::Keyword(Keyword::Await) if cursor.arrow() => Ok(Sym::AWAIT),
TokenKind::Keyword(Keyword::Await) if self.allow_await.0 => {
TokenKind::Keyword((Keyword::Await, _)) if cursor.arrow() => Ok(Sym::AWAIT),
TokenKind::Keyword((Keyword::Await, _)) if self.allow_await.0 => {
// Early Error: It is a Syntax Error if this production has an [Await] parameter and StringValue of Identifier is "await".
Err(ParseError::general(
"Unexpected identifier",
next_token.span().start(),
))
}
TokenKind::Keyword(Keyword::Await) if !self.allow_await.0 => {
TokenKind::Keyword((Keyword::Await, _)) if !self.allow_await.0 => {
if cursor.strict_mode() {
Err(ParseError::general(
"await keyword in binding identifier not allowed in strict mode",

2
boa_engine/src/syntax/parser/statement/return_stm/mod.rs

@ -51,7 +51,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("ReturnStatement", "Parsing");
cursor.expect(Keyword::Return, "return statement", interner)?;
cursor.expect((Keyword::Return, false), "return statement", interner)?;
if let SemicolonResult::Found(tok) = cursor.peek_semicolon(interner)? {
match tok {

26
boa_engine/src/syntax/parser/statement/switch/mod.rs

@ -16,8 +16,8 @@ use std::io::Read;
/// The possible `TokenKind` which indicate the end of a case statement.
const CASE_BREAK_TOKENS: [TokenKind; 3] = [
TokenKind::Punctuator(Punctuator::CloseBlock),
TokenKind::Keyword(Keyword::Case),
TokenKind::Keyword(Keyword::Default),
TokenKind::Keyword((Keyword::Case, false)),
TokenKind::Keyword((Keyword::Default, false)),
];
/// Switch statement parsing.
@ -63,7 +63,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("SwitchStatement", "Parsing");
cursor.expect(Keyword::Switch, "switch statement", interner)?;
cursor.expect((Keyword::Switch, false), "switch statement", interner)?;
cursor.expect(Punctuator::OpenParen, "switch statement", interner)?;
let condition = Expression::new(None, true, self.allow_yield, self.allow_await)
@ -125,8 +125,15 @@ where
let mut default = None;
loop {
match cursor.next(interner)? {
Some(token) if token.kind() == &TokenKind::Keyword(Keyword::Case) => {
let token = cursor.next(interner)?.ok_or(ParseError::AbruptEnd)?;
match token.kind() {
TokenKind::Keyword((Keyword::Case | Keyword::Default, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
token.span().start(),
));
}
TokenKind::Keyword((Keyword::Case, false)) => {
// Case statement.
let cond = Expression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
@ -144,7 +151,7 @@ where
cases.push(node::Case::new(cond, statement_list));
}
Some(token) if token.kind() == &TokenKind::Keyword(Keyword::Default) => {
TokenKind::Keyword((Keyword::Default, false)) => {
if default.is_some() {
// If default has already been defined then it cannot be defined again and to do so is an error.
return Err(ParseError::unexpected(
@ -167,10 +174,8 @@ where
default = Some(statement_list);
}
Some(token) if token.kind() == &TokenKind::Punctuator(Punctuator::CloseBlock) => {
break
}
Some(token) => {
TokenKind::Punctuator(Punctuator::CloseBlock) => break,
_ => {
return Err(ParseError::expected(
["case".to_owned(), "default".to_owned(), "}".to_owned()],
token.to_string(interner),
@ -178,7 +183,6 @@ where
"switch case block",
))
}
None => return Err(ParseError::AbruptEnd),
}
}

2
boa_engine/src/syntax/parser/statement/throw/mod.rs

@ -50,7 +50,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("ThrowStatement", "Parsing");
cursor.expect(Keyword::Throw, "throw statement", interner)?;
cursor.expect((Keyword::Throw, false), "throw statement", interner)?;
cursor.peek_expect_no_lineterminator(0, "throw statement", interner)?;

2
boa_engine/src/syntax/parser/statement/try_stm/catch.rs

@ -57,7 +57,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("Catch", "Parsing");
cursor.expect(Keyword::Catch, "try statement", interner)?;
cursor.expect((Keyword::Catch, false), "try statement", interner)?;
let catch_param = if cursor.next_if(Punctuator::OpenParen, interner)?.is_some() {
let catch_param =
CatchParameter::new(self.allow_yield, self.allow_await).parse(cursor, interner)?;

2
boa_engine/src/syntax/parser/statement/try_stm/finally.rs

@ -52,7 +52,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("Finally", "Parsing");
cursor.expect(Keyword::Finally, "try statement", interner)?;
cursor.expect((Keyword::Finally, false), "try statement", interner)?;
Ok(
Block::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)?

26
boa_engine/src/syntax/parser/statement/try_stm/mod.rs

@ -59,16 +59,21 @@ where
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("TryStatement", "Parsing");
// TRY
cursor.expect(Keyword::Try, "try statement", interner)?;
cursor.expect((Keyword::Try, false), "try statement", interner)?;
let try_clause = Block::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)?;
let next_token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
if next_token.kind() != &TokenKind::Keyword(Keyword::Catch)
&& next_token.kind() != &TokenKind::Keyword(Keyword::Finally)
{
match next_token.kind() {
TokenKind::Keyword((Keyword::Catch | Keyword::Finally, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
next_token.span().start(),
));
}
TokenKind::Keyword((Keyword::Catch | Keyword::Finally, false)) => {}
_ => {
return Err(ParseError::expected(
["catch".to_owned(), "finally".to_owned()],
next_token.to_string(interner),
@ -76,8 +81,9 @@ where
"try statement",
));
}
}
let catch = if next_token.kind() == &TokenKind::Keyword(Keyword::Catch) {
let catch = if next_token.kind() == &TokenKind::Keyword((Keyword::Catch, false)) {
Some(
Catch::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)?,
@ -89,7 +95,13 @@ where
let next_token = cursor.peek(0, interner)?;
let finally_block = if let Some(token) = next_token {
match token.kind() {
TokenKind::Keyword(Keyword::Finally) => Some(
TokenKind::Keyword((Keyword::Finally, true)) => {
return Err(ParseError::general(
"Keyword must not contain escaped characters",
token.span().start(),
));
}
TokenKind::Keyword((Keyword::Finally, false)) => Some(
Finally::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)?,
),

2
boa_engine/src/syntax/parser/statement/variable/mod.rs

@ -60,7 +60,7 @@ where
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("VariableStatement", "Parsing");
cursor.expect(Keyword::Var, "variable statement", interner)?;
cursor.expect((Keyword::Var, false), "variable statement", interner)?;
let decl_list = VariableDeclarationList::new(true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?;

Loading…
Cancel
Save