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. 45
      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. 47
      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. 34
      boa_engine/src/syntax/parser/statement/expression/mod.rs
  29. 105
      boa_engine/src/syntax/parser/statement/if_stm/mod.rs
  30. 28
      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. 38
      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)?; Self::take_identifier_name(cursor, start_pos, self.init)?;
let token_kind = if let Ok(keyword) = identifier_name.parse() { 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 { if cursor.strict_mode() && keyword == Keyword::With {
return Err(Error::Syntax( return Err(Error::Syntax(
"using 'with' statement not allowed in strict mode".into(), "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::True => TokenKind::BooleanLiteral(true),
Keyword::False => TokenKind::BooleanLiteral(false), Keyword::False => TokenKind::BooleanLiteral(false),
Keyword::Null => TokenKind::NullLiteral, Keyword::Null => TokenKind::NullLiteral,
_ => TokenKind::Keyword(keyword), _ => TokenKind::Keyword((keyword, contains_escaped_chars)),
} }
} else { } else {
if cursor.strict_mode() 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 mut interner = Interner::default();
let expected = [ let expected = [
TokenKind::Keyword(Keyword::Var), TokenKind::Keyword((Keyword::Var, false)),
TokenKind::LineTerminator, TokenKind::LineTerminator,
TokenKind::LineTerminator, TokenKind::LineTerminator,
TokenKind::BooleanLiteral(true), TokenKind::BooleanLiteral(true),
@ -52,7 +52,7 @@ fn check_single_line_comment_with_crlf_ending() {
let mut interner = Interner::default(); let mut interner = Interner::default();
let expected = [ let expected = [
TokenKind::Keyword(Keyword::Var), TokenKind::Keyword((Keyword::Var, false)),
TokenKind::LineTerminator, TokenKind::LineTerminator,
TokenKind::LineTerminator, TokenKind::LineTerminator,
TokenKind::BooleanLiteral(true), TokenKind::BooleanLiteral(true),
@ -69,7 +69,7 @@ fn check_multi_line_comment() {
let sym = interner.get_or_intern_static("x"); let sym = interner.get_or_intern_static("x");
let expected = [ let expected = [
TokenKind::Keyword(Keyword::Var), TokenKind::Keyword((Keyword::Var, false)),
TokenKind::LineTerminator, TokenKind::LineTerminator,
TokenKind::identifier(sym), TokenKind::identifier(sym),
]; ];
@ -251,40 +251,40 @@ fn check_keywords() {
let mut interner = Interner::default(); let mut interner = Interner::default();
let expected = [ let expected = [
TokenKind::Keyword(Keyword::Await), TokenKind::Keyword((Keyword::Await, false)),
TokenKind::Keyword(Keyword::Break), TokenKind::Keyword((Keyword::Break, false)),
TokenKind::Keyword(Keyword::Case), TokenKind::Keyword((Keyword::Case, false)),
TokenKind::Keyword(Keyword::Catch), TokenKind::Keyword((Keyword::Catch, false)),
TokenKind::Keyword(Keyword::Class), TokenKind::Keyword((Keyword::Class, false)),
TokenKind::Keyword(Keyword::Const), TokenKind::Keyword((Keyword::Const, false)),
TokenKind::Keyword(Keyword::Continue), TokenKind::Keyword((Keyword::Continue, false)),
TokenKind::Keyword(Keyword::Debugger), TokenKind::Keyword((Keyword::Debugger, false)),
TokenKind::Keyword(Keyword::Default), TokenKind::Keyword((Keyword::Default, false)),
TokenKind::Keyword(Keyword::Delete), TokenKind::Keyword((Keyword::Delete, false)),
TokenKind::Keyword(Keyword::Do), TokenKind::Keyword((Keyword::Do, false)),
TokenKind::Keyword(Keyword::Else), TokenKind::Keyword((Keyword::Else, false)),
TokenKind::Keyword(Keyword::Export), TokenKind::Keyword((Keyword::Export, false)),
TokenKind::Keyword(Keyword::Extends), TokenKind::Keyword((Keyword::Extends, false)),
TokenKind::Keyword(Keyword::Finally), TokenKind::Keyword((Keyword::Finally, false)),
TokenKind::Keyword(Keyword::For), TokenKind::Keyword((Keyword::For, false)),
TokenKind::Keyword(Keyword::Function), TokenKind::Keyword((Keyword::Function, false)),
TokenKind::Keyword(Keyword::If), TokenKind::Keyword((Keyword::If, false)),
TokenKind::Keyword(Keyword::Import), TokenKind::Keyword((Keyword::Import, false)),
TokenKind::Keyword(Keyword::In), TokenKind::Keyword((Keyword::In, false)),
TokenKind::Keyword(Keyword::InstanceOf), TokenKind::Keyword((Keyword::InstanceOf, false)),
TokenKind::Keyword(Keyword::New), TokenKind::Keyword((Keyword::New, false)),
TokenKind::Keyword(Keyword::Return), TokenKind::Keyword((Keyword::Return, false)),
TokenKind::Keyword(Keyword::Super), TokenKind::Keyword((Keyword::Super, false)),
TokenKind::Keyword(Keyword::Switch), TokenKind::Keyword((Keyword::Switch, false)),
TokenKind::Keyword(Keyword::This), TokenKind::Keyword((Keyword::This, false)),
TokenKind::Keyword(Keyword::Throw), TokenKind::Keyword((Keyword::Throw, false)),
TokenKind::Keyword(Keyword::Try), TokenKind::Keyword((Keyword::Try, false)),
TokenKind::Keyword(Keyword::TypeOf), TokenKind::Keyword((Keyword::TypeOf, false)),
TokenKind::Keyword(Keyword::Var), TokenKind::Keyword((Keyword::Var, false)),
TokenKind::Keyword(Keyword::Void), TokenKind::Keyword((Keyword::Void, false)),
TokenKind::Keyword(Keyword::While), TokenKind::Keyword((Keyword::While, false)),
TokenKind::Keyword(Keyword::With), TokenKind::Keyword((Keyword::With, false)),
TokenKind::Keyword(Keyword::Yield), TokenKind::Keyword((Keyword::Yield, false)),
]; ];
expect_tokens(&mut lexer, &expected, &mut interner); 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 a_sym = interner.get_or_intern_static("a");
let hello_sym = interner.get_or_intern_static("hello"); let hello_sym = interner.get_or_intern_static("hello");
let expected = [ let expected = [
TokenKind::Keyword(Keyword::Let), TokenKind::Keyword((Keyword::Let, false)),
TokenKind::identifier(a_sym), TokenKind::identifier(a_sym),
TokenKind::Punctuator(Punctuator::Assign), TokenKind::Punctuator(Punctuator::Assign),
TokenKind::string_literal(hello_sym), TokenKind::string_literal(hello_sym),

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

@ -105,8 +105,8 @@ pub enum TokenKind {
/// A private identifier. /// A private identifier.
PrivateIdentifier(Sym), PrivateIdentifier(Sym),
/// A keyword. /// A keyword and a flag if the keyword contains unicode escaped chars.
Keyword(Keyword), Keyword((Keyword, bool)),
/// A `null` literal. /// A `null` literal.
NullLiteral, NullLiteral,
@ -142,8 +142,8 @@ impl From<bool> for TokenKind {
} }
} }
impl From<Keyword> for TokenKind { impl From<(Keyword, bool)> for TokenKind {
fn from(kw: Keyword) -> Self { fn from(kw: (Keyword, bool)) -> Self {
Self::Keyword(kw) Self::Keyword(kw)
} }
} }
@ -176,11 +176,6 @@ impl TokenKind {
Self::Identifier(ident) Self::Identifier(ident)
} }
/// Creates a `Keyword` token kind.
pub fn keyword(keyword: Keyword) -> Self {
Self::Keyword(keyword)
}
/// Creates a `NumericLiteral` token kind. /// Creates a `NumericLiteral` token kind.
pub fn numeric_literal<L>(lit: L) -> Self pub fn numeric_literal<L>(lit: L) -> Self
where where
@ -229,7 +224,7 @@ impl TokenKind {
Self::EOF => "end of file".to_owned(), Self::EOF => "end of file".to_owned(),
Self::Identifier(ident) => interner.resolve_expect(ident).to_owned(), Self::Identifier(ident) => interner.resolve_expect(ident).to_owned(),
Self::PrivateIdentifier(ident) => format!("#{}", interner.resolve_expect(ident)), 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::NullLiteral => "null".to_owned(),
Self::NumericLiteral(Numeric::Rational(num)) => num.to_string(), Self::NumericLiteral(Numeric::Rational(num)) => num.to_string(),
Self::NumericLiteral(Numeric::Integer(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)? { Ok(if let Some(tok) = cursor.peek(0, interner)? {
matches!( matches!(
tok.kind(), tok.kind(),
TokenKind::Keyword(Keyword::Delete | Keyword::Void | Keyword::TypeOf) TokenKind::Keyword((Keyword::Delete | Keyword::Void | Keyword::TypeOf, _))
| TokenKind::Punctuator( | TokenKind::Punctuator(
Punctuator::Add | Punctuator::Sub | Punctuator::Not | Punctuator::Neg Punctuator::Add | Punctuator::Sub | Punctuator::Not | Punctuator::Neg
) )

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

@ -97,12 +97,12 @@ where
.kind() .kind()
{ {
// [+Yield]YieldExpression[?In, ?Await] // [+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) return YieldExpression::new(self.allow_in, self.allow_await)
.parse(cursor, interner) .parse(cursor, interner)
} }
// ArrowFunction[?In, ?Yield, ?Await] -> ArrowParameters[?Yield, ?Await] -> BindingIdentifier[?Yield, ?Await] // 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) = if let Ok(tok) =
cursor.peek_expect_no_lineterminator(1, "assignment expression", interner) 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"); let _timer = Profiler::global().start_event("YieldExpression", "Parsing");
cursor.expect( cursor.expect(
TokenKind::Keyword(Keyword::Yield), TokenKind::Keyword((Keyword::Yield, false)),
"yield expression", "yield expression",
interner, interner,
)?; )?;
@ -87,7 +87,7 @@ where
| Punctuator::OpenBlock | Punctuator::OpenBlock
| Punctuator::Div, | Punctuator::Div,
) )
| TokenKind::Keyword( | TokenKind::Keyword((
Keyword::Yield Keyword::Yield
| Keyword::Await | Keyword::Await
| Keyword::Delete | Keyword::Delete
@ -98,7 +98,8 @@ where
| Keyword::Function | Keyword::Function
| Keyword::Class | Keyword::Class
| Keyword::Async, | Keyword::Async,
) _,
))
| TokenKind::BooleanLiteral(_) | TokenKind::BooleanLiteral(_)
| TokenKind::NullLiteral | TokenKind::NullLiteral
| TokenKind::StringLiteral(_) | TokenKind::StringLiteral(_)

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

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

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

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

45
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 { fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult {
let _timer = Profiler::global().start_event("MemberExpression", "Parsing"); let _timer = Profiler::global().start_event("MemberExpression", "Parsing");
let mut lhs = if cursor let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
.peek(0, interner)? let mut lhs = match token.kind() {
.ok_or(ParseError::AbruptEnd)? TokenKind::Keyword((Keyword::New, true)) => {
.kind() return Err(ParseError::general(
== &TokenKind::Keyword(Keyword::New) "keyword must not contain escaped characters",
{ token.span().start(),
let _next = cursor.next(interner).expect("new keyword disappeared"); ));
let lhs = self.parse(cursor, interner)?; }
let args = match cursor.peek(0, interner)? { TokenKind::Keyword((Keyword::New, false)) => {
Some(next) if next.kind() == &TokenKind::Punctuator(Punctuator::OpenParen) => { let _next = cursor.next(interner).expect("new keyword disappeared");
Arguments::new(self.allow_yield, self.allow_await).parse(cursor, interner)? let lhs = self.parse(cursor, interner)?;
} let args = match cursor.peek(0, interner)? {
_ => Box::new([]), Some(next) if next.kind() == &TokenKind::Punctuator(Punctuator::OpenParen) => {
}; Arguments::new(self.allow_yield, self.allow_await)
let call_node = Call::new(lhs, args); .parse(cursor, interner)?
}
_ => Box::new([]),
};
let call_node = Call::new(lhs, args);
Node::from(New::from(call_node)) Node::from(New::from(call_node))
} else { }
PrimaryExpression::new(self.name, self.allow_yield, self.allow_await) _ => PrimaryExpression::new(self.name, self.allow_yield, self.allow_await)
.parse(cursor, interner)? .parse(cursor, interner)?,
}; };
while let Some(tok) = cursor.peek(0, interner)? { while let Some(tok) = cursor.peek(0, interner)? {
match tok.kind() { match tok.kind() {
TokenKind::Punctuator(Punctuator::Dot) => { TokenKind::Punctuator(Punctuator::Dot) => {
@ -96,7 +101,7 @@ where
match token.kind() { match token.kind() {
TokenKind::Identifier(name) => lhs = GetConstField::new(lhs, *name).into(), TokenKind::Identifier(name) => lhs = GetConstField::new(lhs, *name).into(),
TokenKind::Keyword(kw) => { TokenKind::Keyword((kw, _)) => {
lhs = GetConstField::new(lhs, kw.to_sym(interner)).into(); lhs = GetConstField::new(lhs, kw.to_sym(interner)).into();
} }
TokenKind::BooleanLiteral(bool) => { 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)? $lower::new($( self.$low_param ),*).parse(cursor, interner)?
).into(); ).into();
} }
TokenKind::Keyword(op) if $( op == $op )||* => { TokenKind::Keyword((op, false)) if $( op == $op )||* => {
let _next = cursor.next(interner).expect("token disappeared"); let _next = cursor.next(interner).expect("token disappeared");
lhs = BinOp::new( lhs = BinOp::new(
op.as_binop().expect("Could not get binary operation."), op.as_binop().expect("Could not get binary operation."),
@ -540,7 +540,13 @@ where
) )
.into(); .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 if op == Keyword::InstanceOf
|| (op == Keyword::In && self.allow_in == AllowIn(true)) => || (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> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("AsyncFunctionExpression", "Parsing"); let _timer = Profiler::global().start_event("AsyncFunctionExpression", "Parsing");
cursor.peek_expect_no_lineterminator(0, "async function expression", interner)?; 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 let name = match cursor
.peek(0, interner)? .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"); let _timer = Profiler::global().start_event("AsyncGeneratorExpression", "Parsing");
cursor.peek_expect_no_lineterminator(0, "async generator expression", interner)?; 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( cursor.expect(
TokenKind::Punctuator(Punctuator::Mul), TokenKind::Punctuator(Punctuator::Mul),
"async generator expression", "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 token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
let name = match token.kind() { 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) BindingIdentifier::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)? .parse(cursor, interner)?
} }

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

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

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

@ -161,14 +161,14 @@ where
))); )));
} }
TokenKind::Identifier(ident) => Identifier::new(*ident), 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". // Early Error: It is a Syntax Error if this production has a [Yield] parameter and StringValue of Identifier is "yield".
return Err(ParseError::general( return Err(ParseError::general(
"Unexpected identifier", "Unexpected identifier",
token.span().start(), 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() { if cursor.strict_mode() {
// Early Error: It is a Syntax Error if the code matched by this production is contained in strict mode code. // Early Error: It is a Syntax Error if the code matched by this production is contained in strict mode code.
return Err(ParseError::general( return Err(ParseError::general(
@ -178,14 +178,14 @@ where
} }
Identifier::new(Sym::YIELD) 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". // Early Error: It is a Syntax Error if this production has an [Await] parameter and StringValue of Identifier is "await".
return Err(ParseError::general( return Err(ParseError::general(
"Unexpected identifier", "Unexpected identifier",
token.span().start(), 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() { if cursor.strict_mode() {
// Early Error: It is a Syntax Error if the code matched by this production is contained in strict mode code. // Early Error: It is a Syntax Error if the code matched by this production is contained in strict mode code.
return Err(ParseError::general( return Err(ParseError::general(
@ -215,25 +215,36 @@ where
} }
//Async [AsyncMethod, AsyncGeneratorMethod] object methods //Async [AsyncMethod, AsyncGeneratorMethod] object methods
if cursor.next_if(Keyword::Async, interner)?.is_some() { let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
cursor.peek_expect_no_lineterminator(0, "Async object methods", interner)?; match token.kind() {
TokenKind::Keyword((Keyword::Async, true)) => {
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?; return Err(ParseError::general(
if let TokenKind::Punctuator(Punctuator::Mul) = token.kind() { "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)?;
if let TokenKind::Punctuator(Punctuator::Mul) = token.kind() {
let (property_name, method) =
AsyncGeneratorMethod::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)?;
return Ok(object::PropertyDefinition::method_definition(
method,
property_name,
));
}
let (property_name, method) = let (property_name, method) =
AsyncGeneratorMethod::new(self.allow_yield, self.allow_await) AsyncMethod::new(self.allow_yield, self.allow_await).parse(cursor, interner)?;
.parse(cursor, interner)?;
return Ok(object::PropertyDefinition::method_definition( return Ok(object::PropertyDefinition::method_definition(
method, method,
property_name, property_name,
)); ));
} }
let (property_name, method) = _ => {}
AsyncMethod::new(self.allow_yield, self.allow_await).parse(cursor, interner)?;
return Ok(object::PropertyDefinition::method_definition(
method,
property_name,
));
} }
if cursor if cursor
@ -465,7 +476,7 @@ where
Numeric::Integer(num) => Node::Const(Const::from(*num)).into(), Numeric::Integer(num) => Node::Const(Const::from(*num)).into(),
Numeric::BigInt(num) => Node::Const(Const::from(num.clone())).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() Node::Const(Const::from(interner.get_or_intern_static(word.as_str()))).into()
} }
TokenKind::NullLiteral => Node::Const(Const::from(Sym::NULL)).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 tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
let token_start = tok.span().start(); let token_start = tok.span().start();
match tok.kind() { 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"); cursor.next(interner)?.expect("Delete keyword vanished");
let position = cursor let position = cursor
.peek(0, interner)? .peek(0, interner)?
@ -93,11 +96,11 @@ where
Ok(node::UnaryOp::new(UnaryOp::Delete, val).into()) 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. cursor.next(interner)?.expect("Void keyword vanished"); // Consume the token.
Ok(node::UnaryOp::new(UnaryOp::Void, self.parse(cursor, interner)?).into()) 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. cursor.next(interner)?.expect("TypeOf keyword vanished"); // Consume the token.
Ok(node::UnaryOp::new(UnaryOp::TypeOf, self.parse(cursor, interner)?).into()) 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, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("BreakStatement", "Parsing"); 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)? { let label = if let SemicolonResult::Found(tok) = cursor.peek_semicolon(interner)? {
match tok { match tok {

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

@ -63,7 +63,7 @@ where
interner: &mut Interner, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("ContinueStatement", "Parsing"); 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)? { let label = if let SemicolonResult::Found(tok) = cursor.peek_semicolon(interner)? {
match tok { 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>, cursor: &mut Cursor<R>,
interner: &mut Interner, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> 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.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)?; 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>, cursor: &mut Cursor<R>,
interner: &mut Interner, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> 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.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)?; cursor.expect(Punctuator::Mul, "async generator declaration", interner)?;
let result = parse_callable_declaration(&self, cursor, 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>, cursor: &mut Cursor<R>,
interner: &mut Interner, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
cursor.expect(Keyword::Class, "class declaration", interner)?; cursor.expect((Keyword::Class, false), "class declaration", interner)?;
let strict = cursor.strict_mode(); let strict = cursor.strict_mode();
cursor.set_strict_mode(true); cursor.set_strict_mode(true);
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?; let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
let name = match token.kind() { 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) BindingIdentifier::new(self.allow_yield, self.allow_await)
.parse(cursor, interner)? .parse(cursor, interner)?
} }
@ -136,12 +136,17 @@ where
interner: &mut Interner, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?; let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
let super_ref = if token.kind() == &TokenKind::Keyword(Keyword::Extends) { let super_ref = match token.kind() {
Some(Box::new( 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)?, ClassHeritage::new(self.allow_yield, self.allow_await).parse(cursor, interner)?,
)) )),
} else { _ => None,
None
}; };
cursor.expect(Punctuator::OpenBlock, "class tail", interner)?; cursor.expect(Punctuator::OpenBlock, "class tail", interner)?;
@ -207,7 +212,7 @@ where
interner: &mut Interner, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
cursor.expect( cursor.expect(
TokenKind::Keyword(Keyword::Extends), TokenKind::Keyword((Keyword::Extends, false)),
"class heritage", "class heritage",
interner, interner,
)?; )?;
@ -592,7 +597,13 @@ where
ClassElementNode::MethodDefinition(property_name, method) 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.next(interner).expect("token disappeared");
cursor.peek_expect_no_lineterminator(0, "Async object methods", interner)?; cursor.peek_expect_no_lineterminator(0, "Async object methods", interner)?;
let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?; 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>, cursor: &mut Cursor<R>,
interner: &mut Interner, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> 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)?; 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>, cursor: &mut Cursor<R>,
interner: &mut Interner, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> 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)?; cursor.expect(Punctuator::Mul, "generator declaration", interner)?;
let result = parse_callable_declaration(&self, cursor, 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)?; let tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match tok.kind() { 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)?; let next_token = cursor.peek(1, interner)?.ok_or(ParseError::AbruptEnd)?;
if let TokenKind::Punctuator(Punctuator::Mul) = next_token.kind() { if let TokenKind::Punctuator(Punctuator::Mul) = next_token.kind() {
GeneratorDeclaration::new(self.allow_yield, self.allow_await, self.is_default) GeneratorDeclaration::new(self.allow_yield, self.allow_await, self.is_default)
@ -87,7 +93,7 @@ where
.map(Node::from) .map(Node::from)
} }
} }
TokenKind::Keyword(Keyword::Async) => { TokenKind::Keyword((Keyword::Async, false)) => {
let next_token = cursor.peek(2, interner)?.ok_or(ParseError::AbruptEnd)?; let next_token = cursor.peek(2, interner)?.ok_or(ParseError::AbruptEnd)?;
if let TokenKind::Punctuator(Punctuator::Mul) = next_token.kind() { if let TokenKind::Punctuator(Punctuator::Mul) = next_token.kind() {
AsyncGeneratorDeclaration::new( AsyncGeneratorDeclaration::new(
@ -103,7 +109,7 @@ where
.map(Node::from) .map(Node::from)
} }
} }
TokenKind::Keyword(Keyword::Class) => { TokenKind::Keyword((Keyword::Class, false)) => {
ClassDeclaration::new(false, false, self.is_default) ClassDeclaration::new(false, false, self.is_default)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .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)?; let tok = cursor.next(interner)?.ok_or(ParseError::AbruptEnd)?;
match tok.kind() { 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_in,
self.allow_yield, self.allow_yield,
self.allow_await, self.allow_await,
@ -82,7 +86,7 @@ where
self.const_init_required, self.const_init_required,
) )
.parse(cursor, interner), .parse(cursor, interner),
TokenKind::Keyword(Keyword::Let) => BindingList::new( TokenKind::Keyword((Keyword::Let, false)) => BindingList::new(
self.allow_in, self.allow_in,
self.allow_yield, self.allow_yield,
self.allow_await, self.allow_await,
@ -182,8 +186,17 @@ where
match cursor.peek_semicolon(interner)? { match cursor.peek_semicolon(interner)? {
SemicolonResult::Found(_) => break, SemicolonResult::Found(_) => break,
SemicolonResult::NotFound(tk) SemicolonResult::NotFound(tk)
if tk.kind() == &TokenKind::Keyword(Keyword::Of) if tk.kind() == &TokenKind::Keyword((Keyword::Of, true))
|| tk.kind() == &TokenKind::Keyword(Keyword::In) => || 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 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)?; let tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match tok.kind() { 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) HoistableDeclaration::new(self.allow_yield, self.allow_await, false)
.parse(cursor, interner) .parse(cursor, interner)
} }
TokenKind::Keyword(Keyword::Const | Keyword::Let) => LexicalDeclaration::new( TokenKind::Keyword((Keyword::Const | Keyword::Let, _)) => LexicalDeclaration::new(
true, true,
self.allow_yield, self.allow_yield,
self.allow_await, self.allow_await,

34
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)?; let next_token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match next_token.kind() { 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( return Err(ParseError::general(
"expected statement", "expected statement",
next_token.span().start(), next_token.span().start(),
)); ));
} }
TokenKind::Keyword(Keyword::Async) => { TokenKind::Keyword((Keyword::Async, false)) => {
let next_token = cursor.peek(1, interner)?.ok_or(ParseError::AbruptEnd)?; let next_token = cursor.peek(1, interner)?.ok_or(ParseError::AbruptEnd)?;
if next_token.kind() == &TokenKind::Keyword(Keyword::Function) { match next_token.kind() {
return Err(ParseError::general( TokenKind::Keyword((Keyword::Function, true)) => {
"expected statement", return Err(ParseError::general(
next_token.span().start(), "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)?; let next_token = cursor.peek(1, interner)?.ok_or(ParseError::AbruptEnd)?;
if next_token.kind() == &TokenKind::Punctuator(Punctuator::OpenBracket) { if next_token.kind() == &TokenKind::Punctuator(Punctuator::OpenBracket) {
return Err(ParseError::general( return Err(ParseError::general(

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

@ -60,7 +60,7 @@ where
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("IfStatement", "Parsing"); 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)?; cursor.expect(Punctuator::OpenParen, "if statement", interner)?;
let condition = Expression::new(None, true, self.allow_yield, self.allow_await) let condition = Expression::new(None, true, self.allow_yield, self.allow_await)
@ -71,61 +71,72 @@ where
.span() .span()
.end(); .end();
let then_node = if !cursor.strict_mode() let strict = cursor.strict_mode();
&& cursor let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
.peek(0, interner)? let then_node = match token.kind() {
.ok_or(ParseError::AbruptEnd)? TokenKind::Keyword((Keyword::Function, _)) if !strict => {
.kind()
== &TokenKind::Keyword(Keyword::Function)
{
// 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)?;
// Early Error: It is a Syntax Error if IsLabelledFunction(the first Statement) is true.
if let Node::FunctionDecl(_) = node {
return Err(ParseError::wrong_function_declaration_non_strict(position));
}
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)
{
// FunctionDeclarations in IfStatement Statement Clauses // FunctionDeclarations in IfStatement Statement Clauses
// https://tc39.es/ecma262/#sec-functiondeclarations-in-ifstatement-statement-clauses // https://tc39.es/ecma262/#sec-functiondeclarations-in-ifstatement-statement-clauses
Some( FunctionDeclaration::new(self.allow_yield, self.allow_await, false)
FunctionDeclaration::new(self.allow_yield, self.allow_await, false) .parse(cursor, interner)?
.parse(cursor, interner)? .into()
.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)?; .parse(cursor, interner)?;
// Early Error: It is a Syntax Error if IsLabelledFunction(the second Statement) is true. // Early Error: It is a Syntax Error if IsLabelledFunction(the first Statement) is true.
if let Node::FunctionDecl(_) = node { 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) node
}
};
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(
FunctionDeclaration::new(self.allow_yield, self.allow_await, false)
.parse(cursor, interner)?
.into(),
)
}
_ => {
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,
));
}
Some(node)
}
}
}
_ => None,
} }
} else { } else {
None None

28
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 _timer = Profiler::global().start_event("DoWhileStatement", "Parsing");
let position = cursor let position = cursor
.expect(Keyword::Do, "do while statement", interner)? .expect((Keyword::Do, false), "do while statement", interner)?
.span() .span()
.end(); .end();
@ -81,17 +81,25 @@ where
} }
let next_token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?; let next_token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match next_token.kind() {
if next_token.kind() != &TokenKind::Keyword(Keyword::While) { TokenKind::Keyword((Keyword::While, true)) => {
return Err(ParseError::expected( return Err(ParseError::general(
["while".to_owned()], "Keyword must not contain escaped characters",
next_token.to_string(interner), next_token.span().start(),
next_token.span(), ));
"do while statement", }
)); TokenKind::Keyword((Keyword::While, false)) => {}
_ => {
return Err(ParseError::expected(
["while".to_owned()],
next_token.to_string(interner),
next_token.span(),
"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)?; 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, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("ForStatement", "Parsing"); 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 let init_position = cursor
.expect(Punctuator::OpenParen, "for statement", interner)? .expect(Punctuator::OpenParen, "for statement", interner)?
.span() .span()
@ -88,7 +88,7 @@ where
.ok_or(ParseError::AbruptEnd)? .ok_or(ParseError::AbruptEnd)?
.kind() .kind()
{ {
TokenKind::Keyword(Keyword::Var) => { TokenKind::Keyword((Keyword::Var, _)) => {
let _next = cursor.next(interner)?; let _next = cursor.next(interner)?;
Some( Some(
VariableDeclarationList::new(false, self.allow_yield, self.allow_await) VariableDeclarationList::new(false, self.allow_yield, self.allow_await)
@ -96,7 +96,7 @@ where
.map(Node::from)?, .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) Declaration::new(self.allow_yield, self.allow_await, false)
.parse(cursor, interner)?, .parse(cursor, interner)?,
), ),
@ -107,8 +107,15 @@ where
), ),
}; };
match (init.as_ref(), cursor.peek(0, interner)?) { let token = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
(Some(init), Some(tok)) if tok.kind() == &TokenKind::Keyword(Keyword::In) => { 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 init = node_to_iterable_loop_initializer(init, init_position)?;
let _next = cursor.next(interner)?; let _next = cursor.next(interner)?;
@ -130,7 +137,7 @@ where
return Ok(ForInLoop::new(init, expr, body).into()); 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 init = node_to_iterable_loop_initializer(init, init_position)?;
let _next = cursor.next(interner)?; let _next = cursor.next(interner)?;

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

@ -56,7 +56,7 @@ where
interner: &mut Interner, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("WhileStatement", "Parsing"); 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)?; 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. // 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-statements-static-semantics-early-errors
// https://tc39.es/ecma262/#sec-labelled-function-declarations // https://tc39.es/ecma262/#sec-labelled-function-declarations
TokenKind::Keyword(Keyword::Function) if strict => { TokenKind::Keyword((Keyword::Function, _)) if strict => {
return Err(ParseError::general( return Err(ParseError::general(
"In strict mode code, functions can only be declared at top level or inside a block.", "In strict mode code, functions can only be declared at top level or inside a block.",
next_token.span().start() next_token.span().start()
)) ))
} }
TokenKind::Keyword(Keyword::Function) => { TokenKind::Keyword((Keyword::Function, _)) => {
FunctionDeclaration::new(self.allow_yield, self.allow_await, false) FunctionDeclaration::new(self.allow_yield, self.allow_await, false)
.parse(cursor, interner)? .parse(cursor, interner)?
.into() .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)?; let tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match tok.kind() { match tok.kind() {
TokenKind::Keyword(Keyword::Await) => AwaitExpression::new(self.allow_yield) TokenKind::Keyword((Keyword::Await, _)) => AwaitExpression::new(self.allow_yield)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from), .map(Node::from),
TokenKind::Keyword(Keyword::If) => { TokenKind::Keyword((Keyword::If, _)) => {
IfStatement::new(self.allow_yield, self.allow_await, self.allow_return) IfStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .map(Node::from)
} }
TokenKind::Keyword(Keyword::Var) => { TokenKind::Keyword((Keyword::Var, _)) => {
VariableStatement::new(self.allow_yield, self.allow_await) VariableStatement::new(self.allow_yield, self.allow_await)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .map(Node::from)
} }
TokenKind::Keyword(Keyword::While) => { TokenKind::Keyword((Keyword::While, _)) => {
WhileStatement::new(self.allow_yield, self.allow_await, self.allow_return) WhileStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .map(Node::from)
} }
TokenKind::Keyword(Keyword::Do) => { TokenKind::Keyword((Keyword::Do, _)) => {
DoWhileStatement::new(self.allow_yield, self.allow_await, self.allow_return) DoWhileStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .map(Node::from)
} }
TokenKind::Keyword(Keyword::For) => { TokenKind::Keyword((Keyword::For, _)) => {
ForStatement::new(self.allow_yield, self.allow_await, self.allow_return) ForStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .map(Node::from)
} }
TokenKind::Keyword(Keyword::Return) => { TokenKind::Keyword((Keyword::Return, _)) => {
if self.allow_return.0 { if self.allow_return.0 {
ReturnStatement::new(self.allow_yield, self.allow_await) ReturnStatement::new(self.allow_yield, self.allow_await)
.parse(cursor, interner) .parse(cursor, interner)
@ -167,27 +167,27 @@ where
)) ))
} }
} }
TokenKind::Keyword(Keyword::Break) => { TokenKind::Keyword((Keyword::Break, _)) => {
BreakStatement::new(self.allow_yield, self.allow_await) BreakStatement::new(self.allow_yield, self.allow_await)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .map(Node::from)
} }
TokenKind::Keyword(Keyword::Continue) => { TokenKind::Keyword((Keyword::Continue, _)) => {
ContinueStatement::new(self.allow_yield, self.allow_await) ContinueStatement::new(self.allow_yield, self.allow_await)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .map(Node::from)
} }
TokenKind::Keyword(Keyword::Try) => { TokenKind::Keyword((Keyword::Try, _)) => {
TryStatement::new(self.allow_yield, self.allow_await, self.allow_return) TryStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .map(Node::from)
} }
TokenKind::Keyword(Keyword::Throw) => { TokenKind::Keyword((Keyword::Throw, _)) => {
ThrowStatement::new(self.allow_yield, self.allow_await) ThrowStatement::new(self.allow_yield, self.allow_await)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .map(Node::from)
} }
TokenKind::Keyword(Keyword::Switch) => { TokenKind::Keyword((Keyword::Switch, _)) => {
SwitchStatement::new(self.allow_yield, self.allow_await, self.allow_return) SwitchStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner) .parse(cursor, interner)
.map(Node::from) .map(Node::from)
@ -471,7 +471,7 @@ where
let tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?; let tok = cursor.peek(0, interner)?.ok_or(ParseError::AbruptEnd)?;
match *tok.kind() { 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 { if strict_mode && self.in_block {
return Err(ParseError::lex(LexError::Syntax( return Err(ParseError::lex(LexError::Syntax(
"Function declaration in blocks not allowed in strict mode".into(), "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) 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) Declaration::new(self.allow_yield, self.allow_await, true).parse(cursor, interner)
} }
_ => Statement::new(self.allow_yield, self.allow_await, self.allow_return) _ => Statement::new(self.allow_yield, self.allow_await, self.allow_return)
@ -555,14 +555,14 @@ where
))) )))
} }
TokenKind::Identifier(ref s) => Ok(*s), 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". // Early Error: It is a Syntax Error if this production has a [Yield] parameter and StringValue of Identifier is "yield".
Err(ParseError::general( Err(ParseError::general(
"Unexpected identifier", "Unexpected identifier",
next_token.span().start(), 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() { if cursor.strict_mode() {
Err(ParseError::general( Err(ParseError::general(
"yield keyword in binding identifier not allowed in strict mode", "yield keyword in binding identifier not allowed in strict mode",
@ -572,15 +572,15 @@ where
Ok(Sym::YIELD) Ok(Sym::YIELD)
} }
} }
TokenKind::Keyword(Keyword::Await) if cursor.arrow() => Ok(Sym::AWAIT), TokenKind::Keyword((Keyword::Await, _)) if cursor.arrow() => Ok(Sym::AWAIT),
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". // Early Error: It is a Syntax Error if this production has an [Await] parameter and StringValue of Identifier is "await".
Err(ParseError::general( Err(ParseError::general(
"Unexpected identifier", "Unexpected identifier",
next_token.span().start(), 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() { if cursor.strict_mode() {
Err(ParseError::general( Err(ParseError::general(
"await keyword in binding identifier not allowed in strict mode", "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, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("ReturnStatement", "Parsing"); 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)? { if let SemicolonResult::Found(tok) = cursor.peek_semicolon(interner)? {
match tok { 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. /// The possible `TokenKind` which indicate the end of a case statement.
const CASE_BREAK_TOKENS: [TokenKind; 3] = [ const CASE_BREAK_TOKENS: [TokenKind; 3] = [
TokenKind::Punctuator(Punctuator::CloseBlock), TokenKind::Punctuator(Punctuator::CloseBlock),
TokenKind::Keyword(Keyword::Case), TokenKind::Keyword((Keyword::Case, false)),
TokenKind::Keyword(Keyword::Default), TokenKind::Keyword((Keyword::Default, false)),
]; ];
/// Switch statement parsing. /// Switch statement parsing.
@ -63,7 +63,7 @@ where
interner: &mut Interner, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("SwitchStatement", "Parsing"); 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)?; cursor.expect(Punctuator::OpenParen, "switch statement", interner)?;
let condition = Expression::new(None, true, self.allow_yield, self.allow_await) let condition = Expression::new(None, true, self.allow_yield, self.allow_await)
@ -125,8 +125,15 @@ where
let mut default = None; let mut default = None;
loop { loop {
match cursor.next(interner)? { let token = cursor.next(interner)?.ok_or(ParseError::AbruptEnd)?;
Some(token) if token.kind() == &TokenKind::Keyword(Keyword::Case) => { 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. // Case statement.
let cond = Expression::new(None, true, self.allow_yield, self.allow_await) let cond = Expression::new(None, true, self.allow_yield, self.allow_await)
.parse(cursor, interner)?; .parse(cursor, interner)?;
@ -144,7 +151,7 @@ where
cases.push(node::Case::new(cond, statement_list)); 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.is_some() {
// If default has already been defined then it cannot be defined again and to do so is an error. // If default has already been defined then it cannot be defined again and to do so is an error.
return Err(ParseError::unexpected( return Err(ParseError::unexpected(
@ -167,10 +174,8 @@ where
default = Some(statement_list); default = Some(statement_list);
} }
Some(token) if token.kind() == &TokenKind::Punctuator(Punctuator::CloseBlock) => { TokenKind::Punctuator(Punctuator::CloseBlock) => break,
break _ => {
}
Some(token) => {
return Err(ParseError::expected( return Err(ParseError::expected(
["case".to_owned(), "default".to_owned(), "}".to_owned()], ["case".to_owned(), "default".to_owned(), "}".to_owned()],
token.to_string(interner), token.to_string(interner),
@ -178,7 +183,6 @@ where
"switch case block", "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, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("ThrowStatement", "Parsing"); 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)?; 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, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("Catch", "Parsing"); 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 = if cursor.next_if(Punctuator::OpenParen, interner)?.is_some() {
let catch_param = let catch_param =
CatchParameter::new(self.allow_yield, self.allow_await).parse(cursor, interner)?; 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, interner: &mut Interner,
) -> Result<Self::Output, ParseError> { ) -> Result<Self::Output, ParseError> {
let _timer = Profiler::global().start_event("Finally", "Parsing"); let _timer = Profiler::global().start_event("Finally", "Parsing");
cursor.expect(Keyword::Finally, "try statement", interner)?; cursor.expect((Keyword::Finally, false), "try statement", interner)?;
Ok( Ok(
Block::new(self.allow_yield, self.allow_await, self.allow_return) Block::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)? .parse(cursor, interner)?

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

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

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

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

Loading…
Cancel
Save