From b3389b7d6724cb7ea5b9e25af88ccc54e8a84547 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 26 Sep 2020 11:00:15 +0100 Subject: [PATCH 01/10] Add strict mode to lex trait --- boa/src/syntax/lexer/comment.rs | 4 ++-- boa/src/syntax/lexer/identifier.rs | 2 +- boa/src/syntax/lexer/mod.rs | 24 +++++++++---------- boa/src/syntax/lexer/number.rs | 13 +++++----- boa/src/syntax/lexer/operator.rs | 2 +- boa/src/syntax/lexer/regex.rs | 2 +- boa/src/syntax/lexer/spread.rs | 2 +- boa/src/syntax/lexer/string.rs | 2 +- boa/src/syntax/lexer/template.rs | 2 +- .../parser/cursor/buffered_lexer/mod.rs | 4 +++- 10 files changed, 29 insertions(+), 28 deletions(-) diff --git a/boa/src/syntax/lexer/comment.rs b/boa/src/syntax/lexer/comment.rs index cedd084ca88..0d50b6294cb 100644 --- a/boa/src/syntax/lexer/comment.rs +++ b/boa/src/syntax/lexer/comment.rs @@ -23,7 +23,7 @@ use std::io::Read; pub(super) struct SingleLineComment; impl Tokenizer for SingleLineComment { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position) -> Result + fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result where R: Read, { @@ -58,7 +58,7 @@ impl Tokenizer for SingleLineComment { pub(super) struct MultiLineComment; impl Tokenizer for MultiLineComment { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position) -> Result + fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/identifier.rs b/boa/src/syntax/lexer/identifier.rs index 15dfecbb7cd..c3d70c01155 100644 --- a/boa/src/syntax/lexer/identifier.rs +++ b/boa/src/syntax/lexer/identifier.rs @@ -31,7 +31,7 @@ impl Identifier { } impl Tokenizer for Identifier { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position) -> Result + fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/mod.rs b/boa/src/syntax/lexer/mod.rs index 4fd8f75c3ab..937733352d7 100644 --- a/boa/src/syntax/lexer/mod.rs +++ b/boa/src/syntax/lexer/mod.rs @@ -48,7 +48,7 @@ pub use token::{Token, TokenKind}; trait Tokenizer { /// Lexes the next token. - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position) -> Result + fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result where R: Read; } @@ -109,7 +109,7 @@ impl Lexer { // that means it could be multiple different tokens depending on the input token. // // As per https://tc39.es/ecma262/#sec-ecmascript-language-lexical-grammar - pub(crate) fn lex_slash_token(&mut self, start: Position) -> Result + pub(crate) fn lex_slash_token(&mut self, start: Position, strict_mode: bool) -> Result where R: Read, { @@ -119,11 +119,11 @@ impl Lexer { match c { '/' => { self.cursor.next_char()?.expect("/ token vanished"); // Consume the '/' - SingleLineComment.lex(&mut self.cursor, start) + SingleLineComment.lex(&mut self.cursor, start, strict_mode) } '*' => { self.cursor.next_char()?.expect("* token vanished"); // Consume the '*' - MultiLineComment.lex(&mut self.cursor, start) + MultiLineComment.lex(&mut self.cursor, start, strict_mode) } ch => { match self.get_goal() { @@ -146,7 +146,7 @@ impl Lexer { } InputElement::RegExp | InputElement::RegExpOrTemplateTail => { // Can be a regular expression. - RegexLiteral.lex(&mut self.cursor, start) + RegexLiteral.lex(&mut self.cursor, start, strict_mode) } } } @@ -188,13 +188,13 @@ impl Lexer { TokenKind::LineTerminator, Span::new(start, self.cursor.pos()), )), - '"' | '\'' => StringLiteral::new(next_chr).lex(&mut self.cursor, start), - '`' => TemplateLiteral.lex(&mut self.cursor, start), + '"' | '\'' => StringLiteral::new(next_chr).lex(&mut self.cursor, start, strict_mode), + '`' => TemplateLiteral.lex(&mut self.cursor, start, strict_mode), _ if next_chr.is_digit(10) => { - NumberLiteral::new(next_chr, strict_mode).lex(&mut self.cursor, start) + NumberLiteral::new(next_chr).lex(&mut self.cursor, start, strict_mode) } _ if next_chr.is_alphabetic() || next_chr == '$' || next_chr == '_' => { - Identifier::new(next_chr).lex(&mut self.cursor, start) + Identifier::new(next_chr).lex(&mut self.cursor, start, strict_mode) } ';' => Ok(Token::new( Punctuator::Semicolon.into(), @@ -204,7 +204,7 @@ impl Lexer { Punctuator::Colon.into(), Span::new(start, self.cursor.pos()), )), - '.' => SpreadLiteral::new().lex(&mut self.cursor, start), + '.' => SpreadLiteral::new().lex(&mut self.cursor, start, strict_mode), '(' => Ok(Token::new( Punctuator::OpenParen.into(), Span::new(start, self.cursor.pos()), @@ -237,9 +237,9 @@ impl Lexer { Punctuator::Question.into(), Span::new(start, self.cursor.pos()), )), - '/' => self.lex_slash_token(start), + '/' => self.lex_slash_token(start, strict_mode), '=' | '*' | '+' | '-' | '%' | '|' | '&' | '^' | '<' | '>' | '!' | '~' => { - Operator::new(next_chr).lex(&mut self.cursor, start) + Operator::new(next_chr).lex(&mut self.cursor, start, strict_mode) } _ => { let details = format!( diff --git a/boa/src/syntax/lexer/number.rs b/boa/src/syntax/lexer/number.rs index 8391a3ee12f..e4cb5a71f59 100644 --- a/boa/src/syntax/lexer/number.rs +++ b/boa/src/syntax/lexer/number.rs @@ -23,14 +23,13 @@ use std::{io::Read, str::FromStr}; /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type #[derive(Debug, Clone, Copy)] pub(super) struct NumberLiteral { - init: char, - strict_mode: bool, + init: char } impl NumberLiteral { /// Creates a new string literal lexer. - pub(super) fn new(init: char, strict_mode: bool) -> Self { - Self { init, strict_mode } + pub(super) fn new(init: char) -> Self { + Self { init } } } @@ -135,7 +134,7 @@ where } impl Tokenizer for NumberLiteral { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position) -> Result + fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result where R: Read, { @@ -187,7 +186,7 @@ impl Tokenizer for NumberLiteral { ch => { if ch.is_digit(8) { // LegacyOctalIntegerLiteral - if self.strict_mode { + if strict_mode { // LegacyOctalIntegerLiteral is forbidden with strict mode true. return Err(Error::syntax( "implicit octal literals are not allowed in strict mode", @@ -205,7 +204,7 @@ impl Tokenizer for NumberLiteral { // Indicates a numerical digit comes after then 0 but it isn't an octal digit // so therefore this must be a number with an unneeded leading 0. This is // forbidden in strict mode. - if self.strict_mode { + if strict_mode { return Err(Error::syntax( "leading 0's are not allowed in strict mode", start_pos, diff --git a/boa/src/syntax/lexer/operator.rs b/boa/src/syntax/lexer/operator.rs index 5aa72c7d559..052039f3f10 100644 --- a/boa/src/syntax/lexer/operator.rs +++ b/boa/src/syntax/lexer/operator.rs @@ -93,7 +93,7 @@ impl Operator { } impl Tokenizer for Operator { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position) -> Result + fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/regex.rs b/boa/src/syntax/lexer/regex.rs index 2367c44d70f..472cd26d6c3 100644 --- a/boa/src/syntax/lexer/regex.rs +++ b/boa/src/syntax/lexer/regex.rs @@ -33,7 +33,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub(super) struct RegexLiteral; impl Tokenizer for RegexLiteral { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position) -> Result + fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/spread.rs b/boa/src/syntax/lexer/spread.rs index cc8e0ad36f9..83a2581c521 100644 --- a/boa/src/syntax/lexer/spread.rs +++ b/boa/src/syntax/lexer/spread.rs @@ -31,7 +31,7 @@ impl SpreadLiteral { } impl Tokenizer for SpreadLiteral { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position) -> Result + fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/string.rs b/boa/src/syntax/lexer/string.rs index 87b999664c8..30e79299c5c 100644 --- a/boa/src/syntax/lexer/string.rs +++ b/boa/src/syntax/lexer/string.rs @@ -51,7 +51,7 @@ enum StringTerminator { } impl Tokenizer for StringLiteral { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position) -> Result + fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/template.rs b/boa/src/syntax/lexer/template.rs index c51763c7f33..72b5c678ee2 100644 --- a/boa/src/syntax/lexer/template.rs +++ b/boa/src/syntax/lexer/template.rs @@ -24,7 +24,7 @@ use std::io::{self, ErrorKind, Read}; pub(super) struct TemplateLiteral; impl Tokenizer for TemplateLiteral { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position) -> Result + fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result where R: Read, { diff --git a/boa/src/syntax/parser/cursor/buffered_lexer/mod.rs b/boa/src/syntax/parser/cursor/buffered_lexer/mod.rs index bed01da9ef0..f7dce89e38a 100644 --- a/boa/src/syntax/parser/cursor/buffered_lexer/mod.rs +++ b/boa/src/syntax/parser/cursor/buffered_lexer/mod.rs @@ -79,7 +79,9 @@ where pub(super) fn lex_regex(&mut self, start: Position) -> Result { let _timer = BoaProfiler::global().start_event("cursor::lex_regex()", "Parsing"); self.set_goal(InputElement::RegExp); - self.lexer.lex_slash_token(start).map_err(|e| e.into()) + + let strict_mode: bool = false; // TODO enable setting strict mode on/off. + self.lexer.lex_slash_token(start, strict_mode).map_err(|e| e.into()) } /// Fills the peeking buffer with the next token. From 0108b8009ca27d50b7911c72520ac11a8755f159 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 26 Sep 2020 11:22:52 +0100 Subject: [PATCH 02/10] Lexer reserved keyword identifier strict mode lexing --- boa/src/syntax/lexer/comment.rs | 14 +++++++-- boa/src/syntax/lexer/identifier.rs | 31 ++++++++++++++++++- boa/src/syntax/lexer/mod.rs | 13 ++++++-- boa/src/syntax/lexer/number.rs | 9 ++++-- boa/src/syntax/lexer/operator.rs | 7 ++++- boa/src/syntax/lexer/regex.rs | 7 ++++- boa/src/syntax/lexer/spread.rs | 7 ++++- boa/src/syntax/lexer/string.rs | 7 ++++- boa/src/syntax/lexer/template.rs | 7 ++++- .../parser/cursor/buffered_lexer/mod.rs | 4 ++- 10 files changed, 93 insertions(+), 13 deletions(-) diff --git a/boa/src/syntax/lexer/comment.rs b/boa/src/syntax/lexer/comment.rs index 0d50b6294cb..9d3a3155813 100644 --- a/boa/src/syntax/lexer/comment.rs +++ b/boa/src/syntax/lexer/comment.rs @@ -23,7 +23,12 @@ use std::io::Read; pub(super) struct SingleLineComment; impl Tokenizer for SingleLineComment { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result + fn lex( + &mut self, + cursor: &mut Cursor, + start_pos: Position, + strict_mode: bool, + ) -> Result where R: Read, { @@ -58,7 +63,12 @@ impl Tokenizer for SingleLineComment { pub(super) struct MultiLineComment; impl Tokenizer for MultiLineComment { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result + fn lex( + &mut self, + cursor: &mut Cursor, + start_pos: Position, + strict_mode: bool, + ) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/identifier.rs b/boa/src/syntax/lexer/identifier.rs index c3d70c01155..0d8081afbf8 100644 --- a/boa/src/syntax/lexer/identifier.rs +++ b/boa/src/syntax/lexer/identifier.rs @@ -10,6 +10,20 @@ use crate::{ }; use std::io::Read; +const STRICT_FORBIDDEN_IDENTIFIERS: [&str; 11] = [ + "eval", + "arguments", + "implements", + "interface", + "let", + "package", + "private", + "protected", + "public", + "static", + "yield", +]; + /// Identifier lexing. /// /// More information: @@ -31,7 +45,12 @@ impl Identifier { } impl Tokenizer for Identifier { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result + fn lex( + &mut self, + cursor: &mut Cursor, + start_pos: Position, + strict_mode: bool, + ) -> Result where R: Read, { @@ -51,6 +70,16 @@ impl Tokenizer for Identifier { if let Ok(keyword) = slice.parse() { TokenKind::Keyword(keyword) } else { + if strict_mode && STRICT_FORBIDDEN_IDENTIFIERS.contains(&slice) { + return Err(Error::Syntax( + format!( + "using future reserved keyword '{}' not allowed in strict mode", + slice + ) + .into(), + start_pos, + )); + } TokenKind::identifier(slice) } } diff --git a/boa/src/syntax/lexer/mod.rs b/boa/src/syntax/lexer/mod.rs index 937733352d7..689b684f06a 100644 --- a/boa/src/syntax/lexer/mod.rs +++ b/boa/src/syntax/lexer/mod.rs @@ -48,7 +48,12 @@ pub use token::{Token, TokenKind}; trait Tokenizer { /// Lexes the next token. - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result + fn lex( + &mut self, + cursor: &mut Cursor, + start_pos: Position, + strict_mode: bool, + ) -> Result where R: Read; } @@ -109,7 +114,11 @@ impl Lexer { // that means it could be multiple different tokens depending on the input token. // // As per https://tc39.es/ecma262/#sec-ecmascript-language-lexical-grammar - pub(crate) fn lex_slash_token(&mut self, start: Position, strict_mode: bool) -> Result + pub(crate) fn lex_slash_token( + &mut self, + start: Position, + strict_mode: bool, + ) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/number.rs b/boa/src/syntax/lexer/number.rs index e4cb5a71f59..1cce22256b4 100644 --- a/boa/src/syntax/lexer/number.rs +++ b/boa/src/syntax/lexer/number.rs @@ -23,7 +23,7 @@ use std::{io::Read, str::FromStr}; /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type #[derive(Debug, Clone, Copy)] pub(super) struct NumberLiteral { - init: char + init: char, } impl NumberLiteral { @@ -134,7 +134,12 @@ where } impl Tokenizer for NumberLiteral { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result + fn lex( + &mut self, + cursor: &mut Cursor, + start_pos: Position, + strict_mode: bool, + ) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/operator.rs b/boa/src/syntax/lexer/operator.rs index 052039f3f10..322d8f53be4 100644 --- a/boa/src/syntax/lexer/operator.rs +++ b/boa/src/syntax/lexer/operator.rs @@ -93,7 +93,12 @@ impl Operator { } impl Tokenizer for Operator { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result + fn lex( + &mut self, + cursor: &mut Cursor, + start_pos: Position, + strict_mode: bool, + ) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/regex.rs b/boa/src/syntax/lexer/regex.rs index 472cd26d6c3..f6c3ecf5a51 100644 --- a/boa/src/syntax/lexer/regex.rs +++ b/boa/src/syntax/lexer/regex.rs @@ -33,7 +33,12 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub(super) struct RegexLiteral; impl Tokenizer for RegexLiteral { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result + fn lex( + &mut self, + cursor: &mut Cursor, + start_pos: Position, + strict_mode: bool, + ) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/spread.rs b/boa/src/syntax/lexer/spread.rs index 83a2581c521..56647be3c8d 100644 --- a/boa/src/syntax/lexer/spread.rs +++ b/boa/src/syntax/lexer/spread.rs @@ -31,7 +31,12 @@ impl SpreadLiteral { } impl Tokenizer for SpreadLiteral { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result + fn lex( + &mut self, + cursor: &mut Cursor, + start_pos: Position, + strict_mode: bool, + ) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/string.rs b/boa/src/syntax/lexer/string.rs index 30e79299c5c..51c97ef5dc3 100644 --- a/boa/src/syntax/lexer/string.rs +++ b/boa/src/syntax/lexer/string.rs @@ -51,7 +51,12 @@ enum StringTerminator { } impl Tokenizer for StringLiteral { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result + fn lex( + &mut self, + cursor: &mut Cursor, + start_pos: Position, + strict_mode: bool, + ) -> Result where R: Read, { diff --git a/boa/src/syntax/lexer/template.rs b/boa/src/syntax/lexer/template.rs index 72b5c678ee2..61e94d37ab5 100644 --- a/boa/src/syntax/lexer/template.rs +++ b/boa/src/syntax/lexer/template.rs @@ -24,7 +24,12 @@ use std::io::{self, ErrorKind, Read}; pub(super) struct TemplateLiteral; impl Tokenizer for TemplateLiteral { - fn lex(&mut self, cursor: &mut Cursor, start_pos: Position, strict_mode: bool) -> Result + fn lex( + &mut self, + cursor: &mut Cursor, + start_pos: Position, + strict_mode: bool, + ) -> Result where R: Read, { diff --git a/boa/src/syntax/parser/cursor/buffered_lexer/mod.rs b/boa/src/syntax/parser/cursor/buffered_lexer/mod.rs index f7dce89e38a..407e58be129 100644 --- a/boa/src/syntax/parser/cursor/buffered_lexer/mod.rs +++ b/boa/src/syntax/parser/cursor/buffered_lexer/mod.rs @@ -81,7 +81,9 @@ where self.set_goal(InputElement::RegExp); let strict_mode: bool = false; // TODO enable setting strict mode on/off. - self.lexer.lex_slash_token(start, strict_mode).map_err(|e| e.into()) + self.lexer + .lex_slash_token(start, strict_mode) + .map_err(|e| e.into()) } /// Fills the peeking buffer with the next token. From 5fb2e64341c4fc9da0f1cc6d3b9872ea008267d4 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 26 Sep 2020 11:47:06 +0100 Subject: [PATCH 03/10] Prevent with statement in strict mode --- boa/src/syntax/lexer/identifier.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/boa/src/syntax/lexer/identifier.rs b/boa/src/syntax/lexer/identifier.rs index 0d8081afbf8..b279ddf3b1f 100644 --- a/boa/src/syntax/lexer/identifier.rs +++ b/boa/src/syntax/lexer/identifier.rs @@ -4,7 +4,7 @@ use super::{Cursor, Error, Tokenizer}; use crate::{ profiler::BoaProfiler, syntax::{ - ast::{Position, Span}, + ast::{Keyword, Position, Span}, lexer::{Token, TokenKind}, }, }; @@ -68,6 +68,12 @@ impl Tokenizer for Identifier { "null" => TokenKind::NullLiteral, slice => { if let Ok(keyword) = slice.parse() { + if strict_mode && keyword == Keyword::With { + return Err(Error::Syntax( + "using 'with' statement not allowed in strict mode".into(), + start_pos, + )); + } TokenKind::Keyword(keyword) } else { if strict_mode && STRICT_FORBIDDEN_IDENTIFIERS.contains(&slice) { From 51595042cc85057323da2535d2289737c4193084 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Thu, 1 Oct 2020 09:22:31 +0100 Subject: [PATCH 04/10] Add strict_mode flag to parse methods --- .../expression/assignment/arrow_function.rs | 19 ++++---- .../expression/assignment/conditional.rs | 8 ++-- .../expression/assignment/exponentiation.rs | 10 ++-- .../parser/expression/assignment/mod.rs | 18 +++---- .../expression/left_hand_side/arguments.rs | 6 +-- .../parser/expression/left_hand_side/call.rs | 12 +++-- .../expression/left_hand_side/member.rs | 13 ++--- .../parser/expression/left_hand_side/mod.rs | 8 ++-- boa/src/syntax/parser/expression/mod.rs | 8 ++-- .../primary/array_initializer/mod.rs | 6 +-- .../expression/primary/function_expression.rs | 8 ++-- .../syntax/parser/expression/primary/mod.rs | 16 +++---- .../primary/object_initializer/mod.rs | 29 +++++++----- boa/src/syntax/parser/expression/unary.rs | 20 ++++---- boa/src/syntax/parser/expression/update.rs | 9 ++-- boa/src/syntax/parser/function/mod.rs | 29 ++++++++---- boa/src/syntax/parser/mod.rs | 13 ++--- boa/src/syntax/parser/statement/block/mod.rs | 4 +- .../syntax/parser/statement/break_stm/mod.rs | 5 +- .../parser/statement/continue_stm/mod.rs | 5 +- .../parser/statement/declaration/hoistable.rs | 14 +++--- .../parser/statement/declaration/lexical.rs | 17 +++---- .../parser/statement/declaration/mod.rs | 8 ++-- .../syntax/parser/statement/expression/mod.rs | 5 +- boa/src/syntax/parser/statement/if_stm/mod.rs | 11 +++-- .../statement/iteration/do_while_statement.rs | 9 ++-- .../statement/iteration/for_statement.rs | 25 ++++++---- .../statement/iteration/while_statement.rs | 9 ++-- boa/src/syntax/parser/statement/mod.rs | 47 ++++++++++--------- .../syntax/parser/statement/return_stm/mod.rs | 5 +- boa/src/syntax/parser/statement/switch/mod.rs | 26 ++++++---- boa/src/syntax/parser/statement/throw/mod.rs | 5 +- .../syntax/parser/statement/try_stm/catch.rs | 13 ++--- .../parser/statement/try_stm/finally.rs | 4 +- .../syntax/parser/statement/try_stm/mod.rs | 13 +++-- .../syntax/parser/statement/variable/mod.rs | 20 ++++---- 36 files changed, 269 insertions(+), 208 deletions(-) diff --git a/boa/src/syntax/parser/expression/assignment/arrow_function.rs b/boa/src/syntax/parser/expression/assignment/arrow_function.rs index a9e36151b32..a1bc2e9b1d3 100644 --- a/boa/src/syntax/parser/expression/assignment/arrow_function.rs +++ b/boa/src/syntax/parser/expression/assignment/arrow_function.rs @@ -68,7 +68,7 @@ where { type Output = ArrowFunctionDecl; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("ArrowFunction", "Parsing"); let next_token = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; @@ -76,12 +76,13 @@ where // CoverParenthesizedExpressionAndArrowParameterList cursor.expect(Punctuator::OpenParen, "arrow function")?; - let params = FormalParameters::new(self.allow_yield, self.allow_await).parse(cursor)?; + let params = FormalParameters::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "arrow function")?; params } else { let param = BindingIdentifier::new(self.allow_yield, self.allow_await) - .parse(cursor) + .parse(cursor, strict_mode) .context("arrow function")?; Box::new([FormalParameter::new(param, None, false)]) }; @@ -89,7 +90,7 @@ where cursor.peek_expect_no_lineterminator(0)?; cursor.expect(TokenKind::Punctuator(Punctuator::Arrow), "arrow function")?; - let body = ConciseBody::new(self.allow_in).parse(cursor)?; + let body = ConciseBody::new(self.allow_in).parse(cursor, strict_mode)?; Ok(ArrowFunctionDecl::new(params, body)) } } @@ -118,16 +119,16 @@ where { type Output = StatementList; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { match cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.kind() { TokenKind::Punctuator(Punctuator::OpenBlock) => { let _ = cursor.next(); - let body = FunctionBody::new(false, false).parse(cursor)?; + let body = FunctionBody::new(false, false).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseBlock, "arrow function")?; Ok(body) } _ => Ok(StatementList::from(vec![Return::new( - ExpressionBody::new(self.allow_in, false).parse(cursor)?, + ExpressionBody::new(self.allow_in, false).parse(cursor, strict_mode)?, None, ) .into()])), @@ -162,7 +163,7 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { - AssignmentExpression::new(self.allow_in, false, self.allow_await).parse(cursor) + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { + AssignmentExpression::new(self.allow_in, false, self.allow_await).parse(cursor, strict_mode) } } diff --git a/boa/src/syntax/parser/expression/assignment/conditional.rs b/boa/src/syntax/parser/expression/assignment/conditional.rs index a45997ae5c0..5a1103698e4 100644 --- a/boa/src/syntax/parser/expression/assignment/conditional.rs +++ b/boa/src/syntax/parser/expression/assignment/conditional.rs @@ -62,24 +62,24 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("ConditionalExpression", "Parsing"); // TODO: coalesce expression let lhs = LogicalORExpression::new(self.allow_in, self.allow_yield, self.allow_await) - .parse(cursor)?; + .parse(cursor, strict_mode)?; if let Some(tok) = cursor.peek(0)? { if tok.kind() == &TokenKind::Punctuator(Punctuator::Question) { cursor.next()?.expect("? character vanished"); // Consume the token. let then_clause = AssignmentExpression::new(self.allow_in, self.allow_yield, self.allow_await) - .parse(cursor)?; + .parse(cursor, strict_mode)?; cursor.expect(Punctuator::Colon, "conditional expression")?; let else_clause = AssignmentExpression::new(self.allow_in, self.allow_yield, self.allow_await) - .parse(cursor)?; + .parse(cursor, strict_mode)?; return Ok(ConditionalOp::new(lhs, then_clause, else_clause).into()); } } diff --git a/boa/src/syntax/parser/expression/assignment/exponentiation.rs b/boa/src/syntax/parser/expression/assignment/exponentiation.rs index e9eac4c9dd9..8e315104d6a 100644 --- a/boa/src/syntax/parser/expression/assignment/exponentiation.rs +++ b/boa/src/syntax/parser/expression/assignment/exponentiation.rs @@ -81,18 +81,20 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("ExponentiationExpression", "Parsing"); if is_unary_expression(cursor)? { - return UnaryExpression::new(self.allow_yield, self.allow_await).parse(cursor); + return UnaryExpression::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode); } - let lhs = UpdateExpression::new(self.allow_yield, self.allow_await).parse(cursor)?; + let lhs = + UpdateExpression::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; if let Some(tok) = cursor.peek(0)? { if let TokenKind::Punctuator(Punctuator::Exp) = tok.kind() { cursor.next()?.expect("** token vanished"); // Consume the token. - return Ok(BinOp::new(NumOp::Exp, lhs, self.parse(cursor)?).into()); + return Ok(BinOp::new(NumOp::Exp, lhs, self.parse(cursor, strict_mode)?).into()); } } Ok(lhs) diff --git a/boa/src/syntax/parser/expression/assignment/mod.rs b/boa/src/syntax/parser/expression/assignment/mod.rs index 6fccf62e029..ccc0d664d59 100644 --- a/boa/src/syntax/parser/expression/assignment/mod.rs +++ b/boa/src/syntax/parser/expression/assignment/mod.rs @@ -78,7 +78,7 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("AssignmentExpression", "Parsing"); cursor.set_goal(InputElement::Div); @@ -95,7 +95,7 @@ where self.allow_yield, self.allow_await, ) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::ArrowFunctionDecl); } } @@ -115,7 +115,7 @@ where self.allow_yield, self.allow_await, ) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::ArrowFunctionDecl); } } @@ -126,7 +126,7 @@ where self.allow_yield, self.allow_await, ) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::ArrowFunctionDecl); } TokenKind::Identifier(_) => { @@ -139,7 +139,7 @@ where self.allow_yield, self.allow_await, ) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::ArrowFunctionDecl); } TokenKind::Punctuator(Punctuator::CloseParen) => { @@ -153,7 +153,7 @@ where self.allow_yield, self.allow_await, ) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::ArrowFunctionDecl); } } @@ -173,7 +173,7 @@ where cursor.set_goal(InputElement::Div); let mut lhs = ConditionalExpression::new(self.allow_in, self.allow_yield, self.allow_await) - .parse(cursor)?; + .parse(cursor, strict_mode)?; // Review if we are trying to assign to an invalid left hand side expression. // TODO: can we avoid cloning? @@ -182,7 +182,7 @@ where TokenKind::Punctuator(Punctuator::Assign) => { cursor.next()?.expect("= token vanished"); // Consume the token. if is_assignable(&lhs) { - lhs = Assign::new(lhs, self.parse(cursor)?).into(); + lhs = Assign::new(lhs, self.parse(cursor, strict_mode)?).into(); } else { return Err(ParseError::lex(LexError::Syntax( "Invalid left-hand side in assignment".into(), @@ -194,7 +194,7 @@ where cursor.next()?.expect("token vanished"); // Consume the token. if is_assignable(&lhs) { let binop = p.as_binop().expect("binop disappeared"); - let expr = self.parse(cursor)?; + let expr = self.parse(cursor, strict_mode)?; lhs = BinOp::new(binop, lhs, expr).into(); } else { diff --git a/boa/src/syntax/parser/expression/left_hand_side/arguments.rs b/boa/src/syntax/parser/expression/left_hand_side/arguments.rs index 7be4886f6cc..6a7b67a8644 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/arguments.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/arguments.rs @@ -56,7 +56,7 @@ where { type Output = Box<[Node]>; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("Arguments", "Parsing"); cursor.expect(Punctuator::OpenParen, "arguments")?; @@ -98,7 +98,7 @@ where args.push( Spread::new( AssignmentExpression::new(true, self.allow_yield, self.allow_await) - .parse(cursor)?, + .parse(cursor, strict_mode)?, ) .into(), ); @@ -106,7 +106,7 @@ where cursor.set_goal(InputElement::RegExp); args.push( AssignmentExpression::new(true, self.allow_yield, self.allow_await) - .parse(cursor)?, + .parse(cursor, strict_mode)?, ); } } diff --git a/boa/src/syntax/parser/expression/left_hand_side/call.rs b/boa/src/syntax/parser/expression/left_hand_side/call.rs index 573288b62b5..49b4cd53cdd 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/call.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/call.rs @@ -62,13 +62,14 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("CallExpression", "Parsing"); let token = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; let mut lhs = if token.kind() == &TokenKind::Punctuator(Punctuator::OpenParen) { - let args = Arguments::new(self.allow_yield, self.allow_await).parse(cursor)?; + let args = + Arguments::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; Node::from(Call::new(self.first_member_expr, args)) } else { let next_token = cursor.next()?.expect("token vanished"); @@ -83,7 +84,8 @@ where let token = tok.clone(); match token.kind() { TokenKind::Punctuator(Punctuator::OpenParen) => { - let args = Arguments::new(self.allow_yield, self.allow_await).parse(cursor)?; + let args = Arguments::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; lhs = Node::from(Call::new(lhs, args)); } TokenKind::Punctuator(Punctuator::Dot) => { @@ -107,8 +109,8 @@ where } TokenKind::Punctuator(Punctuator::OpenBracket) => { let _ = cursor.next()?.ok_or(ParseError::AbruptEnd)?; // We move the parser. - let idx = - Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let idx = Expression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseBracket, "call expression")?; lhs = GetField::new(lhs, idx).into(); } diff --git a/boa/src/syntax/parser/expression/left_hand_side/member.rs b/boa/src/syntax/parser/expression/left_hand_side/member.rs index f7a865d0b01..78c7f1ad444 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/member.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/member.rs @@ -58,20 +58,21 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("MemberExpression", "Parsing"); let mut lhs = if cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.kind() == &TokenKind::Keyword(Keyword::New) { let _ = cursor.next().expect("new keyword disappeared"); - let lhs = self.parse(cursor)?; - let args = Arguments::new(self.allow_yield, self.allow_await).parse(cursor)?; + let lhs = self.parse(cursor, strict_mode)?; + let args = + Arguments::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; let call_node = Call::new(lhs, args); Node::from(New::from(call_node)) } else { - PrimaryExpression::new(self.allow_yield, self.allow_await).parse(cursor)? + PrimaryExpression::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode)? }; while let Some(tok) = cursor.peek(0)? { match tok.kind() { @@ -100,8 +101,8 @@ where cursor .next()? .expect("open bracket punctuator token disappeared"); // We move the parser forward. - let idx = - Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let idx = Expression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseBracket, "member expression")?; lhs = GetField::new(lhs, idx).into(); } diff --git a/boa/src/syntax/parser/expression/left_hand_side/mod.rs b/boa/src/syntax/parser/expression/left_hand_side/mod.rs index a41c6df0c7f..f6bd382dc78 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/mod.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/mod.rs @@ -57,16 +57,18 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("LeftHandSIdeExpression", "Parsing"); cursor.set_goal(InputElement::TemplateTail); // TODO: Implement NewExpression: new MemberExpression - let lhs = MemberExpression::new(self.allow_yield, self.allow_await).parse(cursor)?; + let lhs = + MemberExpression::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; if let Some(tok) = cursor.peek(0)? { if tok.kind() == &TokenKind::Punctuator(Punctuator::OpenParen) { - return CallExpression::new(self.allow_yield, self.allow_await, lhs).parse(cursor); + return CallExpression::new(self.allow_yield, self.allow_await, lhs) + .parse(cursor, strict_mode); } } Ok(lhs) diff --git a/boa/src/syntax/parser/expression/mod.rs b/boa/src/syntax/parser/expression/mod.rs index cb88a3174f3..a9f55635be9 100644 --- a/boa/src/syntax/parser/expression/mod.rs +++ b/boa/src/syntax/parser/expression/mod.rs @@ -61,14 +61,14 @@ macro_rules! expression { ($name:ident, $lower:ident, [$( $op:path ),*], [$( $lo { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool)-> ParseResult { let _timer = BoaProfiler::global().start_event($profile, "Parsing"); if $goal.is_some() { cursor.set_goal($goal.unwrap()); } - let mut lhs = $lower::new($( self.$low_param ),*).parse(cursor)?; + let mut lhs = $lower::new($( self.$low_param ),*).parse(cursor, strict_mode)?; while let Some(tok) = cursor.peek(0)? { match *tok.kind() { TokenKind::Punctuator(op) if $( op == $op )||* => { @@ -76,7 +76,7 @@ macro_rules! expression { ($name:ident, $lower:ident, [$( $op:path ),*], [$( $lo lhs = BinOp::new( op.as_binop().expect("Could not get binary operation."), lhs, - $lower::new($( self.$low_param ),*).parse(cursor)? + $lower::new($( self.$low_param ),*).parse(cursor, strict_mode)? ).into(); } TokenKind::Keyword(op) if $( op == $op )||* => { @@ -84,7 +84,7 @@ macro_rules! expression { ($name:ident, $lower:ident, [$( $op:path ),*], [$( $lo lhs = BinOp::new( op.as_binop().expect("Could not get binary operation."), lhs, - $lower::new($( self.$low_param ),*).parse(cursor)? + $lower::new($( self.$low_param ),*).parse(cursor, strict_mode)? ).into(); } _ => break diff --git a/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs b/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs index 427e7f8cd73..d6a747b3dc4 100644 --- a/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs +++ b/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs @@ -60,7 +60,7 @@ where { type Output = ArrayDecl; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("ArrayLiteral", "Parsing"); let mut elements = Vec::new(); @@ -78,12 +78,12 @@ where if cursor.next_if(Punctuator::Spread)?.is_some() { let node = AssignmentExpression::new(true, self.allow_yield, self.allow_await) - .parse(cursor)?; + .parse(cursor, strict_mode)?; elements.push(Spread::new(node).into()); } else { elements.push( AssignmentExpression::new(true, self.allow_yield, self.allow_await) - .parse(cursor)?, + .parse(cursor, strict_mode)?, ); } cursor.next_if(Punctuator::Comma)?; diff --git a/boa/src/syntax/parser/expression/primary/function_expression.rs b/boa/src/syntax/parser/expression/primary/function_expression.rs index 25840ada6fa..46877c65291 100644 --- a/boa/src/syntax/parser/expression/primary/function_expression.rs +++ b/boa/src/syntax/parser/expression/primary/function_expression.rs @@ -39,7 +39,7 @@ where { type Output = FunctionExpr; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("FunctionExpression", "Parsing"); let name = if let Some(token) = cursor.peek(0)? { @@ -47,7 +47,7 @@ where TokenKind::Identifier(_) | TokenKind::Keyword(Keyword::Yield) | TokenKind::Keyword(Keyword::Await) => { - Some(BindingIdentifier::new(false, false).parse(cursor)?) + Some(BindingIdentifier::new(false, false).parse(cursor, strict_mode)?) } _ => None, } @@ -57,12 +57,12 @@ where cursor.expect(Punctuator::OpenParen, "function expression")?; - let params = FormalParameters::new(false, false).parse(cursor)?; + let params = FormalParameters::new(false, false).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "function expression")?; cursor.expect(Punctuator::OpenBlock, "function expression")?; - let body = FunctionBody::new(false, false).parse(cursor)?; + let body = FunctionBody::new(false, false).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseBlock, "function expression")?; diff --git a/boa/src/syntax/parser/expression/primary/mod.rs b/boa/src/syntax/parser/expression/primary/mod.rs index 50cc95cc8af..a0347283fbf 100644 --- a/boa/src/syntax/parser/expression/primary/mod.rs +++ b/boa/src/syntax/parser/expression/primary/mod.rs @@ -67,33 +67,33 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("PrimaryExpression", "Parsing"); let tok = cursor.next()?.ok_or(ParseError::AbruptEnd)?; match tok.kind() { TokenKind::Keyword(Keyword::This) => Ok(Node::This), - TokenKind::Keyword(Keyword::Function) => { - FunctionExpression.parse(cursor).map(Node::from) - } + TokenKind::Keyword(Keyword::Function) => FunctionExpression + .parse(cursor, strict_mode) + .map(Node::from), TokenKind::Punctuator(Punctuator::OpenParen) => { cursor.set_goal(InputElement::RegExp); - let expr = - Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let expr = Expression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "primary expression")?; Ok(expr) } TokenKind::Punctuator(Punctuator::OpenBracket) => { cursor.set_goal(InputElement::RegExp); ArrayLiteral::new(self.allow_yield, self.allow_await) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::ArrayDecl) } TokenKind::Punctuator(Punctuator::OpenBlock) => { cursor.set_goal(InputElement::RegExp); Ok(ObjectLiteral::new(self.allow_yield, self.allow_await) - .parse(cursor)? + .parse(cursor, strict_mode)? .into()) } TokenKind::BooleanLiteral(boolean) => Ok(Const::from(*boolean).into()), diff --git a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs index 7ba38ac3ab3..4cebe1286c9 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs @@ -60,7 +60,7 @@ where { type Output = Object; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("ObjectLiteral", "Parsing"); let mut elements = Vec::new(); @@ -69,8 +69,10 @@ where break; } - elements - .push(PropertyDefinition::new(self.allow_yield, self.allow_await).parse(cursor)?); + elements.push( + PropertyDefinition::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?, + ); if cursor.next_if(Punctuator::CloseBlock)?.is_some() { break; @@ -125,19 +127,19 @@ where { type Output = node::PropertyDefinition; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("PropertyDefinition", "Parsing"); if cursor.next_if(Punctuator::Spread)?.is_some() { let node = AssignmentExpression::new(true, self.allow_yield, self.allow_await) - .parse(cursor)?; + .parse(cursor, strict_mode)?; return Ok(node::PropertyDefinition::SpreadObject(node)); } let prop_name = cursor.next()?.ok_or(ParseError::AbruptEnd)?.to_string(); if cursor.next_if(Punctuator::Colon)?.is_some() { let val = AssignmentExpression::new(true, self.allow_yield, self.allow_await) - .parse(cursor)?; + .parse(cursor, strict_mode)?; return Ok(node::PropertyDefinition::property(prop_name, val)); } @@ -147,7 +149,7 @@ where || ["get", "set"].contains(&prop_name.as_str()) { return MethodDefinition::new(self.allow_yield, self.allow_await, prop_name) - .parse(cursor); + .parse(cursor, strict_mode); } let pos = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.span().start(); @@ -190,7 +192,7 @@ where { type Output = node::PropertyDefinition; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("MethodDefinition", "Parsing"); let (methodkind, prop_name, params) = match self.identifier.as_str() { @@ -201,7 +203,7 @@ where "property method definition", )?; let first_param = cursor.peek(0)?.expect("current token disappeared").clone(); - let params = FormalParameters::new(false, false).parse(cursor)?; + let params = FormalParameters::new(false, false).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "method definition")?; if idn == "get" { if !params.is_empty() { @@ -222,7 +224,7 @@ where } } prop_name => { - let params = FormalParameters::new(false, false).parse(cursor)?; + let params = FormalParameters::new(false, false).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "method definition")?; ( MethodDefinitionKind::Ordinary, @@ -236,7 +238,7 @@ where TokenKind::Punctuator(Punctuator::OpenBlock), "property method definition", )?; - let body = FunctionBody::new(false, false).parse(cursor)?; + let body = FunctionBody::new(false, false).parse(cursor, strict_mode)?; cursor.expect( TokenKind::Punctuator(Punctuator::CloseBlock), "property method definition", @@ -289,10 +291,11 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("Initializer", "Parsing"); cursor.expect(Punctuator::Assign, "initializer")?; - AssignmentExpression::new(self.allow_in, self.allow_yield, self.allow_await).parse(cursor) + AssignmentExpression::new(self.allow_in, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode) } } diff --git a/boa/src/syntax/parser/expression/unary.rs b/boa/src/syntax/parser/expression/unary.rs index 4966224b6c7..e38f75aef96 100644 --- a/boa/src/syntax/parser/expression/unary.rs +++ b/boa/src/syntax/parser/expression/unary.rs @@ -58,40 +58,42 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("UnaryExpression", "Parsing"); let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; match tok.kind() { TokenKind::Keyword(Keyword::Delete) => { cursor.next()?.expect("Delete keyword vanished"); // Consume the token. - Ok(node::UnaryOp::new(UnaryOp::Delete, self.parse(cursor)?).into()) + Ok(node::UnaryOp::new(UnaryOp::Delete, self.parse(cursor, strict_mode)?).into()) } TokenKind::Keyword(Keyword::Void) => { cursor.next()?.expect("Void keyword vanished"); // Consume the token. - Ok(node::UnaryOp::new(UnaryOp::Void, self.parse(cursor)?).into()) + Ok(node::UnaryOp::new(UnaryOp::Void, self.parse(cursor, strict_mode)?).into()) } TokenKind::Keyword(Keyword::TypeOf) => { cursor.next()?.expect("TypeOf keyword vanished"); // Consume the token. - Ok(node::UnaryOp::new(UnaryOp::TypeOf, self.parse(cursor)?).into()) + Ok(node::UnaryOp::new(UnaryOp::TypeOf, self.parse(cursor, strict_mode)?).into()) } TokenKind::Punctuator(Punctuator::Add) => { cursor.next()?.expect("+ token vanished"); // Consume the token. - Ok(node::UnaryOp::new(UnaryOp::Plus, self.parse(cursor)?).into()) + Ok(node::UnaryOp::new(UnaryOp::Plus, self.parse(cursor, strict_mode)?).into()) } TokenKind::Punctuator(Punctuator::Sub) => { cursor.next()?.expect("- token vanished"); // Consume the token. - Ok(node::UnaryOp::new(UnaryOp::Minus, self.parse(cursor)?).into()) + Ok(node::UnaryOp::new(UnaryOp::Minus, self.parse(cursor, strict_mode)?).into()) } TokenKind::Punctuator(Punctuator::Neg) => { cursor.next()?.expect("~ token vanished"); // Consume the token. - Ok(node::UnaryOp::new(UnaryOp::Tilde, self.parse(cursor)?).into()) + Ok(node::UnaryOp::new(UnaryOp::Tilde, self.parse(cursor, strict_mode)?).into()) } TokenKind::Punctuator(Punctuator::Not) => { cursor.next()?.expect("! token vanished"); // Consume the token. - Ok(node::UnaryOp::new(UnaryOp::Not, self.parse(cursor)?).into()) + Ok(node::UnaryOp::new(UnaryOp::Not, self.parse(cursor, strict_mode)?).into()) + } + _ => { + UpdateExpression::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode) } - _ => UpdateExpression::new(self.allow_yield, self.allow_await).parse(cursor), } } } diff --git a/boa/src/syntax/parser/expression/update.rs b/boa/src/syntax/parser/expression/update.rs index 6491770b1c9..0005db31d0b 100644 --- a/boa/src/syntax/parser/expression/update.rs +++ b/boa/src/syntax/parser/expression/update.rs @@ -49,7 +49,7 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("UpdateExpression", "Parsing"); let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; @@ -59,7 +59,7 @@ where return Ok(node::UnaryOp::new( UnaryOp::IncrementPre, LeftHandSideExpression::new(self.allow_yield, self.allow_await) - .parse(cursor)?, + .parse(cursor, strict_mode)?, ) .into()); } @@ -68,14 +68,15 @@ where return Ok(node::UnaryOp::new( UnaryOp::DecrementPre, LeftHandSideExpression::new(self.allow_yield, self.allow_await) - .parse(cursor)?, + .parse(cursor, strict_mode)?, ) .into()); } _ => {} } - let lhs = LeftHandSideExpression::new(self.allow_yield, self.allow_await).parse(cursor)?; + let lhs = LeftHandSideExpression::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; if let Some(tok) = cursor.peek(0)? { match tok.kind() { TokenKind::Punctuator(Punctuator::Inc) => { diff --git a/boa/src/syntax/parser/function/mod.rs b/boa/src/syntax/parser/function/mod.rs index 382bb5f9f84..f65f34e3276 100644 --- a/boa/src/syntax/parser/function/mod.rs +++ b/boa/src/syntax/parser/function/mod.rs @@ -61,7 +61,7 @@ where { type Output = Box<[node::FormalParameter]>; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("FormalParameters", "Parsing"); cursor.set_goal(InputElement::RegExp); @@ -79,9 +79,11 @@ where let next_param = match cursor.peek(0)? { Some(tok) if tok.kind() == &TokenKind::Punctuator(Punctuator::Spread) => { rest_param = true; - FunctionRestParameter::new(self.allow_yield, self.allow_await).parse(cursor)? + FunctionRestParameter::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)? } - _ => FormalParameter::new(self.allow_yield, self.allow_await).parse(cursor)?, + _ => FormalParameter::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?, }; params.push(next_param); @@ -150,11 +152,12 @@ where { type Output = node::FormalParameter; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("BindingRestElement", "Parsing"); cursor.expect(Punctuator::Spread, "rest parameter")?; - let param = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; + let param = BindingIdentifier::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; // TODO: BindingPattern Ok(Self::Output::new(param, None, true)) @@ -195,17 +198,21 @@ where { type Output = node::FormalParameter; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("FormalParameter", "Parsing"); // TODO: BindingPattern - let param = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; + let param = BindingIdentifier::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; let init = if let Some(t) = cursor.peek(0)? { // Check that this is an initilizer before attempting parse. if *t.kind() == TokenKind::Punctuator(Punctuator::Assign) { - Some(Initializer::new(true, self.allow_yield, self.allow_await).parse(cursor)?) + Some( + Initializer::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?, + ) } else { None } @@ -257,14 +264,16 @@ where { type Output = node::StatementList; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("FunctionStatementList", "Parsing"); if let Some(tk) = cursor.peek(0)? { if tk.kind() == &Punctuator::CloseBlock.into() { return Ok(Vec::new().into()); } + // If kind() == " or ' then check for strict directive. } - StatementList::new(self.allow_yield, self.allow_await, true, true).parse(cursor) + StatementList::new(self.allow_yield, self.allow_await, true, true) + .parse(cursor, strict_mode) } } diff --git a/boa/src/syntax/parser/mod.rs b/boa/src/syntax/parser/mod.rs index b5199b2822a..d4bf28837e5 100644 --- a/boa/src/syntax/parser/mod.rs +++ b/boa/src/syntax/parser/mod.rs @@ -28,7 +28,7 @@ where /// Parses the token stream using the current parser. /// /// This method needs to be provided by the implementor type. - fn parse(self, cursor: &mut Cursor) -> Result; + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result; } /// Boolean representing if the parser should allow a `yield` keyword. @@ -101,7 +101,7 @@ impl Parser { where R: Read, { - Script.parse(&mut self.cursor) + Script.parse(&mut self.cursor, false) } } @@ -120,9 +120,10 @@ where { type Output = StatementList; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { if cursor.peek(0)?.is_some() { - ScriptBody.parse(cursor) + // TODO - Setting global strict mode directive. + ScriptBody.parse(cursor, strict_mode) } else { Ok(StatementList::from(Vec::new())) } @@ -144,7 +145,7 @@ where { type Output = StatementList; - fn parse(self, cursor: &mut Cursor) -> Result { - self::statement::StatementList::new(false, false, false, false).parse(cursor) + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { + self::statement::StatementList::new(false, false, false, false).parse(cursor, strict_mode) } } diff --git a/boa/src/syntax/parser/statement/block/mod.rs b/boa/src/syntax/parser/statement/block/mod.rs index 4ab0bf86a98..fffde8cb354 100644 --- a/boa/src/syntax/parser/statement/block/mod.rs +++ b/boa/src/syntax/parser/statement/block/mod.rs @@ -68,7 +68,7 @@ where { type Output = node::Block; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("Block", "Parsing"); cursor.expect(Punctuator::OpenBlock, "block")?; if let Some(tk) = cursor.peek(0)? { @@ -80,7 +80,7 @@ where let statement_list = StatementList::new(self.allow_yield, self.allow_await, self.allow_return, true) - .parse(cursor) + .parse(cursor, strict_mode) .map(node::Block::from)?; cursor.expect(Punctuator::CloseBlock, "block")?; diff --git a/boa/src/syntax/parser/statement/break_stm/mod.rs b/boa/src/syntax/parser/statement/break_stm/mod.rs index bc0cc70e9f0..9d54cd754c3 100644 --- a/boa/src/syntax/parser/statement/break_stm/mod.rs +++ b/boa/src/syntax/parser/statement/break_stm/mod.rs @@ -60,7 +60,7 @@ where { type Output = Break; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("BreakStatement", "Parsing"); cursor.expect(Keyword::Break, "break statement")?; @@ -74,7 +74,8 @@ where None } else { - let label = LabelIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; + let label = LabelIdentifier::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect_semicolon("break statement")?; Some(label) diff --git a/boa/src/syntax/parser/statement/continue_stm/mod.rs b/boa/src/syntax/parser/statement/continue_stm/mod.rs index 48fed421bbe..0195cfdfbc0 100644 --- a/boa/src/syntax/parser/statement/continue_stm/mod.rs +++ b/boa/src/syntax/parser/statement/continue_stm/mod.rs @@ -59,7 +59,7 @@ where { type Output = Continue; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("ContinueStatement", "Parsing"); cursor.expect(Keyword::Continue, "continue statement")?; @@ -73,7 +73,8 @@ where None } else { - let label = LabelIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; + let label = LabelIdentifier::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect_semicolon("continue statement")?; Some(label) diff --git a/boa/src/syntax/parser/statement/declaration/hoistable.rs b/boa/src/syntax/parser/statement/declaration/hoistable.rs index 1f18c099762..a5c115551d1 100644 --- a/boa/src/syntax/parser/statement/declaration/hoistable.rs +++ b/boa/src/syntax/parser/statement/declaration/hoistable.rs @@ -53,11 +53,11 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("HoistableDeclaration", "Parsing"); // TODO: check for generators and async functions + generators FunctionDeclaration::new(self.allow_yield, self.allow_await, self.is_default) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } } @@ -99,20 +99,22 @@ where { type Output = FunctionDecl; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { cursor.expect(Keyword::Function, "function declaration")?; // TODO: If self.is_default, then this can be empty. - let name = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; + let name = BindingIdentifier::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect(Punctuator::OpenParen, "function declaration")?; - let params = FormalParameters::new(false, false).parse(cursor)?; + let params = FormalParameters::new(false, false).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "function declaration")?; cursor.expect(Punctuator::OpenBlock, "function declaration")?; - let body = FunctionBody::new(self.allow_yield, self.allow_await).parse(cursor)?; + let body = + FunctionBody::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseBlock, "function declaration")?; diff --git a/boa/src/syntax/parser/statement/declaration/lexical.rs b/boa/src/syntax/parser/statement/declaration/lexical.rs index e816f5eb485..be43ceeffda 100644 --- a/boa/src/syntax/parser/statement/declaration/lexical.rs +++ b/boa/src/syntax/parser/statement/declaration/lexical.rs @@ -61,18 +61,18 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("LexicalDeclaration", "Parsing"); let tok = cursor.next()?.ok_or(ParseError::AbruptEnd)?; match tok.kind() { TokenKind::Keyword(Keyword::Const) => { BindingList::new(self.allow_in, self.allow_yield, self.allow_await, true) - .parse(cursor) + .parse(cursor, strict_mode) } TokenKind::Keyword(Keyword::Let) => { BindingList::new(self.allow_in, self.allow_yield, self.allow_await, false) - .parse(cursor) + .parse(cursor, strict_mode) } _ => unreachable!("unknown token found: {:?}", tok), } @@ -119,7 +119,7 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("BindingList", "Parsing"); // Create vectors to store the variable declarations @@ -130,7 +130,7 @@ where loop { let (ident, init) = LexicalBinding::new(self.allow_in, self.allow_yield, self.allow_await) - .parse(cursor)?; + .parse(cursor, strict_mode)?; if self.is_const { if let Some(init) = init { @@ -209,16 +209,17 @@ where { type Output = (Box, Option); - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("LexicalBinding", "Parsing"); - let ident = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; + let ident = BindingIdentifier::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; let init = if let Some(t) = cursor.peek(0)? { if *t.kind() == TokenKind::Punctuator(Punctuator::Assign) { Some( Initializer::new(self.allow_in, self.allow_yield, self.allow_await) - .parse(cursor)?, + .parse(cursor, strict_mode)?, ) } else { None diff --git a/boa/src/syntax/parser/statement/declaration/mod.rs b/boa/src/syntax/parser/statement/declaration/mod.rs index cba21cdc027..1a7ddb8414c 100644 --- a/boa/src/syntax/parser/statement/declaration/mod.rs +++ b/boa/src/syntax/parser/statement/declaration/mod.rs @@ -56,16 +56,18 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("Declaration", "Parsing"); let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; match tok.kind() { TokenKind::Keyword(Keyword::Function) => { - HoistableDeclaration::new(self.allow_yield, self.allow_await, false).parse(cursor) + HoistableDeclaration::new(self.allow_yield, self.allow_await, false) + .parse(cursor, strict_mode) } TokenKind::Keyword(Keyword::Const) | TokenKind::Keyword(Keyword::Let) => { - LexicalDeclaration::new(true, self.allow_yield, self.allow_await).parse(cursor) + LexicalDeclaration::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode) } _ => unreachable!("unknown token found: {:?}", tok), } diff --git a/boa/src/syntax/parser/statement/expression/mod.rs b/boa/src/syntax/parser/statement/expression/mod.rs index 7140d330690..b3b6778527f 100644 --- a/boa/src/syntax/parser/statement/expression/mod.rs +++ b/boa/src/syntax/parser/statement/expression/mod.rs @@ -40,10 +40,11 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> ParseResult { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("ExpressionStatement", "Parsing"); // TODO: lookahead - let expr = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let expr = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; cursor.expect_semicolon("expression statement")?; diff --git a/boa/src/syntax/parser/statement/if_stm/mod.rs b/boa/src/syntax/parser/statement/if_stm/mod.rs index 4ec7931dc0b..6e622ac3568 100644 --- a/boa/src/syntax/parser/statement/if_stm/mod.rs +++ b/boa/src/syntax/parser/statement/if_stm/mod.rs @@ -56,24 +56,25 @@ where { type Output = If; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("IfStatement", "Parsing"); cursor.expect(Keyword::If, "if statement")?; cursor.expect(Punctuator::OpenParen, "if statement")?; - let cond = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let cond = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "if statement")?; - let then_stm = - Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; + let then_stm = Statement::new(self.allow_yield, self.allow_await, self.allow_return) + .parse(cursor, strict_mode)?; let else_stm = if let Some(else_tok) = cursor.peek(0)? { if else_tok.kind() == &TokenKind::Keyword(Keyword::Else) { cursor.next()?.expect("else token vanished"); Some( Statement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor)?, + .parse(cursor, strict_mode)?, ) } else { None diff --git a/boa/src/syntax/parser/statement/iteration/do_while_statement.rs b/boa/src/syntax/parser/statement/iteration/do_while_statement.rs index 5314d548560..407b3ea2c4c 100644 --- a/boa/src/syntax/parser/statement/iteration/do_while_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/do_while_statement.rs @@ -61,12 +61,12 @@ where { type Output = DoWhileLoop; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("DoWhileStatement", "Parsing"); cursor.expect(Keyword::Do, "do while statement")?; - let body = - Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; + let body = Statement::new(self.allow_yield, self.allow_await, self.allow_return) + .parse(cursor, strict_mode)?; let next_token = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; @@ -82,7 +82,8 @@ where cursor.expect(Punctuator::OpenParen, "do while statement")?; - let cond = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let cond = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "do while statement")?; diff --git a/boa/src/syntax/parser/statement/iteration/for_statement.rs b/boa/src/syntax/parser/statement/iteration/for_statement.rs index 8e53392fb73..46774a99694 100644 --- a/boa/src/syntax/parser/statement/iteration/for_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/for_statement.rs @@ -67,7 +67,7 @@ where { type Output = ForLoop; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("ForStatement", "Parsing"); cursor.expect(Keyword::For, "for statement")?; cursor.expect(Punctuator::OpenParen, "for statement")?; @@ -77,15 +77,18 @@ where let _ = cursor.next()?; Some( VariableDeclarationList::new(false, self.allow_yield, self.allow_await) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from)?, ) } - TokenKind::Keyword(Keyword::Let) | TokenKind::Keyword(Keyword::Const) => { - Some(Declaration::new(self.allow_yield, self.allow_await).parse(cursor)?) - } + TokenKind::Keyword(Keyword::Let) | TokenKind::Keyword(Keyword::Const) => Some( + Declaration::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode)?, + ), TokenKind::Punctuator(Punctuator::Semicolon) => None, - _ => Some(Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?), + _ => Some( + Expression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?, + ), }; // TODO: for..in, for..of @@ -104,7 +107,8 @@ where let cond = if cursor.next_if(Punctuator::Semicolon)?.is_some() { Const::from(true).into() } else { - let step = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let step = Expression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect(Punctuator::Semicolon, "for statement")?; step }; @@ -112,7 +116,8 @@ where let step = if cursor.next_if(Punctuator::CloseParen)?.is_some() { None } else { - let step = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let step = Expression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect( TokenKind::Punctuator(Punctuator::CloseParen), "for statement", @@ -120,8 +125,8 @@ where Some(step) }; - let body = - Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; + let body = Statement::new(self.allow_yield, self.allow_await, self.allow_return) + .parse(cursor, strict_mode)?; // TODO: do not encapsulate the `for` in a block just to have an inner scope. Ok(ForLoop::new(init, cond, step, body)) diff --git a/boa/src/syntax/parser/statement/iteration/while_statement.rs b/boa/src/syntax/parser/statement/iteration/while_statement.rs index c8b59a99900..3dd132a28f1 100644 --- a/boa/src/syntax/parser/statement/iteration/while_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/while_statement.rs @@ -52,18 +52,19 @@ where { type Output = WhileLoop; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("WhileStatement", "Parsing"); cursor.expect(Keyword::While, "while statement")?; cursor.expect(Punctuator::OpenParen, "while statement")?; - let cond = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let cond = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "while statement")?; - let body = - Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; + let body = Statement::new(self.allow_yield, self.allow_await, self.allow_return) + .parse(cursor, strict_mode)?; Ok(WhileLoop::new(cond, body)) } diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index 6b93bdc7e88..cad4d7a6f25 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -100,7 +100,7 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("Statement", "Parsing"); // TODO: add BreakableStatement and divide Whiles, fors and so on to another place. let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; @@ -108,33 +108,33 @@ where match tok.kind() { TokenKind::Keyword(Keyword::If) => { IfStatement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } TokenKind::Keyword(Keyword::Var) => { VariableStatement::new(self.allow_yield, self.allow_await) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } TokenKind::Keyword(Keyword::While) => { WhileStatement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } TokenKind::Keyword(Keyword::Do) => { DoWhileStatement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } TokenKind::Keyword(Keyword::For) => { ForStatement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } TokenKind::Keyword(Keyword::Return) => { if self.allow_return.0 { ReturnStatement::new(self.allow_yield, self.allow_await) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } else { Err(ParseError::unexpected(tok.clone(), "statement")) @@ -142,36 +142,37 @@ where } TokenKind::Keyword(Keyword::Break) => { BreakStatement::new(self.allow_yield, self.allow_await) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } TokenKind::Keyword(Keyword::Continue) => { ContinueStatement::new(self.allow_yield, self.allow_await) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } TokenKind::Keyword(Keyword::Try) => { TryStatement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } TokenKind::Keyword(Keyword::Throw) => { ThrowStatement::new(self.allow_yield, self.allow_await) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } TokenKind::Keyword(Keyword::Switch) => { SwitchStatement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } TokenKind::Punctuator(Punctuator::OpenBlock) => { BlockStatement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor) + .parse(cursor, strict_mode) .map(Node::from) } // TODO: https://tc39.es/ecma262/#prod-LabelledStatement - _ => ExpressionStatement::new(self.allow_yield, self.allow_await).parse(cursor), + _ => ExpressionStatement::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode), } } } @@ -228,6 +229,7 @@ impl StatementList { self, cursor: &mut Cursor, break_nodes: &[TokenKind], + strict_mode: bool, ) -> Result where R: Read, @@ -245,7 +247,7 @@ impl StatementList { let item = StatementListItem::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor)?; + .parse(cursor, strict_mode)?; items.push(item); @@ -265,7 +267,7 @@ where { type Output = node::StatementList; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("StatementList", "Parsing"); let mut items = Vec::new(); @@ -290,7 +292,7 @@ where let item = StatementListItem::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor)?; + .parse(cursor, strict_mode)?; items.push(item); // move the cursor forward for any consecutive semicolon. @@ -342,7 +344,7 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("StatementListItem", "Parsing"); let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; @@ -350,11 +352,10 @@ where TokenKind::Keyword(Keyword::Function) | TokenKind::Keyword(Keyword::Const) | TokenKind::Keyword(Keyword::Let) => { - Declaration::new(self.allow_yield, self.allow_await).parse(cursor) - } - _ => { - Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor) + Declaration::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode) } + _ => Statement::new(self.allow_yield, self.allow_await, self.allow_return) + .parse(cursor, strict_mode), } } } @@ -401,7 +402,7 @@ where { type Output = Box; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("BindingIdentifier", "Parsing"); // TODO: strict mode. diff --git a/boa/src/syntax/parser/statement/return_stm/mod.rs b/boa/src/syntax/parser/statement/return_stm/mod.rs index 83e8e77e66b..aff434256ee 100644 --- a/boa/src/syntax/parser/statement/return_stm/mod.rs +++ b/boa/src/syntax/parser/statement/return_stm/mod.rs @@ -50,7 +50,7 @@ where { type Output = Return; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("ReturnStatement", "Parsing"); cursor.expect(Keyword::Return, "return statement")?; @@ -65,7 +65,8 @@ where return Ok(Return::new::, Option<_>>(None, None)); } - let expr = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let expr = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; cursor.expect_semicolon("return statement")?; diff --git a/boa/src/syntax/parser/statement/switch/mod.rs b/boa/src/syntax/parser/statement/switch/mod.rs index f19a6104a3c..b3f1d5d8eee 100644 --- a/boa/src/syntax/parser/statement/switch/mod.rs +++ b/boa/src/syntax/parser/statement/switch/mod.rs @@ -59,17 +59,19 @@ where { type Output = Switch; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("SwitchStatement", "Parsing"); cursor.expect(Keyword::Switch, "switch statement")?; cursor.expect(Punctuator::OpenParen, "switch statement")?; - let condition = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let condition = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "switch statement")?; let (cases, default) = - CaseBlock::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; + CaseBlock::new(self.allow_yield, self.allow_await, self.allow_return) + .parse(cursor, strict_mode)?; Ok(Switch::new(condition, cases, default)) } @@ -110,7 +112,7 @@ where { type Output = (Box<[node::Case]>, Option); - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { cursor.expect(Punctuator::OpenBlock, "switch case block")?; let mut cases = Vec::new(); @@ -120,8 +122,8 @@ where match cursor.next()? { Some(token) if token.kind() == &TokenKind::Keyword(Keyword::Case) => { // Case statement. - let cond = - Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let cond = Expression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect(Punctuator::Colon, "switch case block")?; @@ -131,7 +133,11 @@ where self.allow_return, true, ) - .parse_generalised(cursor, &CASE_BREAK_TOKENS)?; + .parse_generalised( + cursor, + &CASE_BREAK_TOKENS, + strict_mode, + )?; cases.push(node::Case::new(cond, statement_list)); } @@ -152,7 +158,11 @@ where self.allow_return, true, ) - .parse_generalised(cursor, &CASE_BREAK_TOKENS)?; + .parse_generalised( + cursor, + &CASE_BREAK_TOKENS, + strict_mode, + )?; default = Some(statement_list); } diff --git a/boa/src/syntax/parser/statement/throw/mod.rs b/boa/src/syntax/parser/statement/throw/mod.rs index 00563512716..dfc8fe92079 100644 --- a/boa/src/syntax/parser/statement/throw/mod.rs +++ b/boa/src/syntax/parser/statement/throw/mod.rs @@ -46,13 +46,14 @@ where { type Output = Throw; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("ThrowStatement", "Parsing"); cursor.expect(Keyword::Throw, "throw statement")?; cursor.peek_expect_no_lineterminator(0)?; - let expr = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let expr = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; if let Some(tok) = cursor.peek(0)? { if tok.kind() == &TokenKind::Punctuator(Punctuator::Semicolon) { let _ = cursor.next(); diff --git a/boa/src/syntax/parser/statement/try_stm/catch.rs b/boa/src/syntax/parser/statement/try_stm/catch.rs index 23bdcaecb0c..42bce8936e6 100644 --- a/boa/src/syntax/parser/statement/try_stm/catch.rs +++ b/boa/src/syntax/parser/statement/try_stm/catch.rs @@ -51,12 +51,12 @@ where { type Output = node::Catch; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("Catch", "Parsing"); cursor.expect(Keyword::Catch, "try statement")?; let catch_param = if cursor.next_if(Punctuator::OpenParen)?.is_some() { - let catch_param = - CatchParameter::new(self.allow_yield, self.allow_await).parse(cursor)?; + let catch_param = CatchParameter::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "catch in try statement")?; Some(catch_param) } else { @@ -66,7 +66,8 @@ where // Catch block Ok(node::Catch::new::<_, Identifier, _>( catch_param, - Block::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?, + Block::new(self.allow_yield, self.allow_await, self.allow_return) + .parse(cursor, strict_mode)?, )) } } @@ -105,10 +106,10 @@ where { type Output = Identifier; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { // TODO: should accept BindingPattern BindingIdentifier::new(self.allow_yield, self.allow_await) - .parse(cursor) + .parse(cursor, strict_mode) .map(Identifier::from) } } diff --git a/boa/src/syntax/parser/statement/try_stm/finally.rs b/boa/src/syntax/parser/statement/try_stm/finally.rs index 125d57df9dd..690b9d51c61 100644 --- a/boa/src/syntax/parser/statement/try_stm/finally.rs +++ b/boa/src/syntax/parser/statement/try_stm/finally.rs @@ -48,12 +48,12 @@ where { type Output = node::Finally; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("Finally", "Parsing"); cursor.expect(Keyword::Finally, "try statement")?; Ok( Block::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor)? + .parse(cursor, strict_mode)? .into(), ) } diff --git a/boa/src/syntax/parser/statement/try_stm/mod.rs b/boa/src/syntax/parser/statement/try_stm/mod.rs index e554d48ea18..543f4d03ea9 100644 --- a/boa/src/syntax/parser/statement/try_stm/mod.rs +++ b/boa/src/syntax/parser/statement/try_stm/mod.rs @@ -55,13 +55,13 @@ where { type Output = Try; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("TryStatement", "Parsing"); // TRY cursor.expect(Keyword::Try, "try statement")?; - let try_clause = - Block::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; + let try_clause = Block::new(self.allow_yield, self.allow_await, self.allow_return) + .parse(cursor, strict_mode)?; let next_token = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; @@ -79,7 +79,10 @@ where } let catch = if next_token.kind() == &TokenKind::Keyword(Keyword::Catch) { - Some(Catch::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?) + Some( + Catch::new(self.allow_yield, self.allow_await, self.allow_return) + .parse(cursor, strict_mode)?, + ) } else { None }; @@ -89,7 +92,7 @@ where match token.kind() { TokenKind::Keyword(Keyword::Finally) => Some( Finally::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor)?, + .parse(cursor, strict_mode)?, ), _ => None, } diff --git a/boa/src/syntax/parser/statement/variable/mod.rs b/boa/src/syntax/parser/statement/variable/mod.rs index f65f62e06a7..6b6a4ef3bfb 100644 --- a/boa/src/syntax/parser/statement/variable/mod.rs +++ b/boa/src/syntax/parser/statement/variable/mod.rs @@ -54,12 +54,12 @@ where { type Output = VarDeclList; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("VariableStatement", "Parsing"); cursor.expect(Keyword::Var, "variable statement")?; - let decl_list = - VariableDeclarationList::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let decl_list = VariableDeclarationList::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect_semicolon("variable statement")?; @@ -108,13 +108,13 @@ where { type Output = VarDeclList; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let mut list = Vec::new(); loop { list.push( VariableDeclaration::new(self.allow_in, self.allow_yield, self.allow_await) - .parse(cursor)?, + .parse(cursor, strict_mode)?, ); match cursor.peek_semicolon()? { @@ -166,14 +166,18 @@ where { type Output = VarDecl; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { // TODO: BindingPattern - let name = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; + let name = BindingIdentifier::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; let init = if let Some(t) = cursor.peek(0)? { if *t.kind() == TokenKind::Punctuator(Punctuator::Assign) { - Some(Initializer::new(true, self.allow_yield, self.allow_await).parse(cursor)?) + Some( + Initializer::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?, + ) } else { None } From 0a032d37e70184d17d40daa6f5b71604ef915d80 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 4 Oct 2020 10:56:44 +0100 Subject: [PATCH 05/10] Enable function scope strict mode --- boa/src/syntax/parser/function/mod.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/boa/src/syntax/parser/function/mod.rs b/boa/src/syntax/parser/function/mod.rs index f65f34e3276..e9cfe1440f4 100644 --- a/boa/src/syntax/parser/function/mod.rs +++ b/boa/src/syntax/parser/function/mod.rs @@ -266,14 +266,23 @@ where fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("FunctionStatementList", "Parsing"); + + let mut func_scope_strict_mode = strict_mode; if let Some(tk) = cursor.peek(0)? { - if tk.kind() == &Punctuator::CloseBlock.into() { - return Ok(Vec::new().into()); + match tk.kind() { + TokenKind::Punctuator(Punctuator::CloseBlock) => { + return Ok(Vec::new().into()); + } + TokenKind::StringLiteral(string) | TokenKind::TemplateLiteral(string) => { + if string == &"use strict".into() { + func_scope_strict_mode = true; + } + } + _ => {} } - // If kind() == " or ' then check for strict directive. } StatementList::new(self.allow_yield, self.allow_await, true, true) - .parse(cursor, strict_mode) + .parse(cursor, func_scope_strict_mode) } } From 4ce7db10124f8d65fce5d2735c054a7714f02e29 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 4 Oct 2020 11:05:36 +0100 Subject: [PATCH 06/10] Script scope strict mode --- boa/src/syntax/parser/mod.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/boa/src/syntax/parser/mod.rs b/boa/src/syntax/parser/mod.rs index d4bf28837e5..09af3a2a103 100644 --- a/boa/src/syntax/parser/mod.rs +++ b/boa/src/syntax/parser/mod.rs @@ -9,7 +9,7 @@ mod statement; mod tests; pub use self::error::{ParseError, ParseResult}; -use crate::syntax::ast::node::StatementList; +use crate::syntax::{ast::node::StatementList, lexer::TokenKind}; use cursor::Cursor; @@ -121,11 +121,18 @@ where type Output = StatementList; fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { - if cursor.peek(0)?.is_some() { - // TODO - Setting global strict mode directive. - ScriptBody.parse(cursor, strict_mode) - } else { - Ok(StatementList::from(Vec::new())) + match cursor.peek(0)? { + Some(tok) => match tok.kind() { + TokenKind::StringLiteral(string) | TokenKind::TemplateLiteral(string) => { + if string == &"use strict".into() { + ScriptBody.parse(cursor, true) + } else { + ScriptBody.parse(cursor, strict_mode) + } + } + _ => ScriptBody.parse(cursor, strict_mode), + }, + None => Ok(StatementList::from(Vec::new())), } } } From 51c3c4a34e2cc59ae1313667922936539ebd6532 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 4 Oct 2020 11:34:55 +0100 Subject: [PATCH 07/10] Delete statement strict mode --- boa/src/syntax/parser/expression/unary.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/boa/src/syntax/parser/expression/unary.rs b/boa/src/syntax/parser/expression/unary.rs index e38f75aef96..ed6d3968d0a 100644 --- a/boa/src/syntax/parser/expression/unary.rs +++ b/boa/src/syntax/parser/expression/unary.rs @@ -15,7 +15,7 @@ use crate::{ op::UnaryOp, Keyword, Punctuator, }, - lexer::TokenKind, + lexer::{Error as LexError, TokenKind}, parser::{ expression::update::UpdateExpression, AllowAwait, AllowYield, Cursor, ParseError, ParseResult, TokenParser, @@ -61,11 +61,23 @@ where fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> ParseResult { let _timer = BoaProfiler::global().start_event("UnaryExpression", "Parsing"); - let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; + // TODO: can we avoid cloning? + let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.clone(); match tok.kind() { TokenKind::Keyword(Keyword::Delete) => { cursor.next()?.expect("Delete keyword vanished"); // Consume the token. - Ok(node::UnaryOp::new(UnaryOp::Delete, self.parse(cursor, strict_mode)?).into()) + let val = self.parse(cursor, strict_mode)?; + + if strict_mode { + if let Node::Identifier(_) = val { + return Err(ParseError::lex(LexError::Syntax( + "Delete statements not allowed in strict mode".into(), + tok.span().start(), + ))); + } + } + + Ok(node::UnaryOp::new(UnaryOp::Delete, val).into()) } TokenKind::Keyword(Keyword::Void) => { cursor.next()?.expect("Void keyword vanished"); // Consume the token. From ff983cb047c7f612e75126d412dcffe49bcb27da Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 4 Oct 2020 11:48:25 +0100 Subject: [PATCH 08/10] Function decl in block in strict mode --- boa/src/syntax/parser/function/mod.rs | 2 +- boa/src/syntax/parser/mod.rs | 3 +- boa/src/syntax/parser/statement/block/mod.rs | 13 ++++-- boa/src/syntax/parser/statement/mod.rs | 42 ++++++++++++++----- boa/src/syntax/parser/statement/switch/mod.rs | 2 + 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/boa/src/syntax/parser/function/mod.rs b/boa/src/syntax/parser/function/mod.rs index e9cfe1440f4..9bf5f3f15ba 100644 --- a/boa/src/syntax/parser/function/mod.rs +++ b/boa/src/syntax/parser/function/mod.rs @@ -282,7 +282,7 @@ where } } - StatementList::new(self.allow_yield, self.allow_await, true, true) + StatementList::new(self.allow_yield, self.allow_await, true, true, true) .parse(cursor, func_scope_strict_mode) } } diff --git a/boa/src/syntax/parser/mod.rs b/boa/src/syntax/parser/mod.rs index 09af3a2a103..7e558522243 100644 --- a/boa/src/syntax/parser/mod.rs +++ b/boa/src/syntax/parser/mod.rs @@ -153,6 +153,7 @@ where type Output = StatementList; fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { - self::statement::StatementList::new(false, false, false, false).parse(cursor, strict_mode) + self::statement::StatementList::new(false, false, false, false, true) + .parse(cursor, strict_mode) } } diff --git a/boa/src/syntax/parser/statement/block/mod.rs b/boa/src/syntax/parser/statement/block/mod.rs index fffde8cb354..9773f2467e0 100644 --- a/boa/src/syntax/parser/statement/block/mod.rs +++ b/boa/src/syntax/parser/statement/block/mod.rs @@ -78,10 +78,15 @@ where } } - let statement_list = - StatementList::new(self.allow_yield, self.allow_await, self.allow_return, true) - .parse(cursor, strict_mode) - .map(node::Block::from)?; + let statement_list = StatementList::new( + self.allow_yield, + self.allow_await, + self.allow_return, + true, + false, + ) + .parse(cursor, strict_mode) + .map(node::Block::from)?; cursor.expect(Punctuator::CloseBlock, "block")?; Ok(statement_list) diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index cad4d7a6f25..058429fac3f 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -37,7 +37,7 @@ use self::{ use super::{AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser}; -use crate::syntax::lexer::TokenKind; +use crate::syntax::lexer::{Error as LexError, TokenKind}; use crate::{ syntax::ast::{node, Keyword, Node, Punctuator}, BoaProfiler, @@ -191,6 +191,7 @@ pub(super) struct StatementList { allow_await: AllowAwait, allow_return: AllowReturn, break_when_closingbraces: bool, + in_block: bool, } impl StatementList { @@ -200,6 +201,7 @@ impl StatementList { allow_await: A, allow_return: R, break_when_closingbraces: bool, + in_block: bool, ) -> Self where Y: Into, @@ -211,6 +213,7 @@ impl StatementList { allow_await: allow_await.into(), allow_return: allow_return.into(), break_when_closingbraces, + in_block, } } @@ -245,9 +248,13 @@ impl StatementList { return Err(ParseError::AbruptEnd); } - let item = - StatementListItem::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor, strict_mode)?; + let item = StatementListItem::new( + self.allow_yield, + self.allow_await, + self.allow_return, + self.in_block, + ) + .parse(cursor, strict_mode)?; items.push(item); @@ -290,9 +297,13 @@ where _ => {} } - let item = - StatementListItem::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor, strict_mode)?; + let item = StatementListItem::new( + self.allow_yield, + self.allow_await, + self.allow_return, + self.in_block, + ) + .parse(cursor, strict_mode)?; items.push(item); // move the cursor forward for any consecutive semicolon. @@ -320,11 +331,12 @@ struct StatementListItem { allow_yield: AllowYield, allow_await: AllowAwait, allow_return: AllowReturn, + in_block: bool, } impl StatementListItem { /// Creates a new `StatementListItem` parser. - fn new(allow_yield: Y, allow_await: A, allow_return: R) -> Self + fn new(allow_yield: Y, allow_await: A, allow_return: R, in_block: bool) -> Self where Y: Into, A: Into, @@ -334,6 +346,7 @@ impl StatementListItem { allow_yield: allow_yield.into(), allow_await: allow_await.into(), allow_return: allow_return.into(), + in_block, } } } @@ -349,9 +362,16 @@ where let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; match *tok.kind() { - TokenKind::Keyword(Keyword::Function) - | TokenKind::Keyword(Keyword::Const) - | TokenKind::Keyword(Keyword::Let) => { + TokenKind::Keyword(Keyword::Function) => { + if strict_mode && self.in_block { + return Err(ParseError::lex(LexError::Syntax( + "Function declaration in blocks not allowed in strict mode".into(), + tok.span().start(), + ))); + } + Declaration::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode) + } + TokenKind::Keyword(Keyword::Const) | TokenKind::Keyword(Keyword::Let) => { Declaration::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode) } _ => Statement::new(self.allow_yield, self.allow_await, self.allow_return) diff --git a/boa/src/syntax/parser/statement/switch/mod.rs b/boa/src/syntax/parser/statement/switch/mod.rs index b3f1d5d8eee..5438435a569 100644 --- a/boa/src/syntax/parser/statement/switch/mod.rs +++ b/boa/src/syntax/parser/statement/switch/mod.rs @@ -132,6 +132,7 @@ where self.allow_await, self.allow_return, true, + false, ) .parse_generalised( cursor, @@ -157,6 +158,7 @@ where self.allow_await, self.allow_return, true, + false, ) .parse_generalised( cursor, From c3d41aabada647647b8da5958b96297a619cd704 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 4 Oct 2020 11:56:11 +0100 Subject: [PATCH 09/10] Fix merge --- .../parser/statement/iteration/for_statement.rs | 13 +++++++------ .../syntax/parser/statement/labelled_stm/mod.rs | 9 +++++---- boa/src/syntax/parser/statement/mod.rs | 14 +++++++++----- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/boa/src/syntax/parser/statement/iteration/for_statement.rs b/boa/src/syntax/parser/statement/iteration/for_statement.rs index d50e0ff4978..782cf676eea 100644 --- a/boa/src/syntax/parser/statement/iteration/for_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/for_statement.rs @@ -81,9 +81,10 @@ where .map(Node::from)?, ) } - TokenKind::Keyword(Keyword::Let) | TokenKind::Keyword(Keyword::Const) => { - Some(Declaration::new(self.allow_yield, self.allow_await, false).parse(cursor, strict_mode)?) - } + TokenKind::Keyword(Keyword::Let) | TokenKind::Keyword(Keyword::Const) => Some( + Declaration::new(self.allow_yield, self.allow_await, false) + .parse(cursor, strict_mode)?, + ), TokenKind::Punctuator(Punctuator::Semicolon) => None, _ => Some( Expression::new(true, self.allow_yield, self.allow_await) @@ -98,11 +99,11 @@ where } Some(tok) if tok.kind() == &TokenKind::Keyword(Keyword::Of) && init.is_some() => { let _ = cursor.next(); - let iterable = - Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; + let iterable = Expression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, strict_mode)?; cursor.expect(Punctuator::CloseParen, "for of statement")?; let body = Statement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor)?; + .parse(cursor, strict_mode)?; return Ok(ForOfLoop::new(init.unwrap(), iterable, body).into()); } _ => {} diff --git a/boa/src/syntax/parser/statement/labelled_stm/mod.rs b/boa/src/syntax/parser/statement/labelled_stm/mod.rs index 231a5c0b8a1..1db955813bd 100644 --- a/boa/src/syntax/parser/statement/labelled_stm/mod.rs +++ b/boa/src/syntax/parser/statement/labelled_stm/mod.rs @@ -47,12 +47,13 @@ where { type Output = Node; - fn parse(self, cursor: &mut Cursor) -> Result { + fn parse(self, cursor: &mut Cursor, strict_mode: bool) -> Result { let _timer = BoaProfiler::global().start_event("Label", "Parsing"); - let name = LabelIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; + let name = + LabelIdentifier::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode)?; cursor.expect(Punctuator::Colon, "Labelled Statement")?; - let mut stmt = - Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; + let mut stmt = Statement::new(self.allow_yield, self.allow_await, self.allow_return) + .parse(cursor, strict_mode)?; set_label_for_node(&mut stmt, name); Ok(stmt) diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index 9459fef786b..b3a3994b621 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -41,7 +41,7 @@ use super::{AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser use crate::{ syntax::{ ast::{node, Keyword, Node, Punctuator}, - lexer::{InputElement, TokenKind, Error as LexError}, + lexer::{Error as LexError, InputElement, TokenKind}, }, BoaProfiler, }; @@ -193,10 +193,12 @@ where .map(Node::from); } - ExpressionStatement::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode) + ExpressionStatement::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode) } - _ => ExpressionStatement::new(self.allow_yield, self.allow_await).parse(cursor, strict_mode), + _ => ExpressionStatement::new(self.allow_yield, self.allow_await) + .parse(cursor, strict_mode), } } } @@ -393,10 +395,12 @@ where tok.span().start(), ))); } - Declaration::new(self.allow_yield, self.allow_await, true).parse(cursor, strict_mode) + Declaration::new(self.allow_yield, self.allow_await, true) + .parse(cursor, strict_mode) } TokenKind::Keyword(Keyword::Const) | TokenKind::Keyword(Keyword::Let) => { - Declaration::new(self.allow_yield, self.allow_await, true).parse(cursor, strict_mode) + Declaration::new(self.allow_yield, self.allow_await, true) + .parse(cursor, strict_mode) } _ => Statement::new(self.allow_yield, self.allow_await, self.allow_return) .parse(cursor, strict_mode), From b58365af0de15fe61e4418a293362c1378a07c16 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 4 Oct 2020 12:49:53 +0100 Subject: [PATCH 10/10] Strict mode code tests --- boa/src/exec/tests.rs | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/boa/src/exec/tests.rs b/boa/src/exec/tests.rs index 7ffd08e366d..6331ffd6649 100644 --- a/boa/src/exec/tests.rs +++ b/boa/src/exec/tests.rs @@ -1383,3 +1383,132 @@ fn test_identifier_op() { let scenario = "break = 1"; assert_eq!(&exec(scenario), "\"SyntaxError\": \"expected token \'identifier\', got \'=\' in binding identifier at line 1, col 7\""); } + +#[test] +fn test_strict_mode_octal() { + // Checks as per https://tc39.es/ecma262/#sec-literals-numeric-literals that 0 prefix + // octal number literal syntax is a syntax error in strict mode. + + let scenario = r#" + 'use strict'; + var n = 023; + "#; + + let mut engine = Context::new(); + + let string = dbg!(forward(&mut engine, scenario)); + + assert!(string.starts_with("Uncaught \"SyntaxError\": ")); + assert!(string.contains("1:3")); +} + +#[test] +fn test_strict_mode_with() { + // Checks as per https://tc39.es/ecma262/#sec-with-statement-static-semantics-early-errors + // that a with statement is an error in strict mode code. + + let scenario = r#" + 'use strict'; + function f(x, o) { + with (o) { + console.log(x); + } + } + "#; + + let mut engine = Context::new(); + + let string = dbg!(forward(&mut engine, scenario)); + + assert!(string.starts_with("Uncaught \"SyntaxError\": ")); + assert!(string.contains("3:5")); +} + +#[test] +fn test_strict_mode_delete() { + // Checks as per https://tc39.es/ecma262/#sec-delete-operator-static-semantics-early-errors + // that delete on a variable name is an error in strict mode code. + + let scenario = r#" + 'use strict'; + let x = 10; + delete x; + "#; + + let mut engine = Context::new(); + + let string = dbg!(forward(&mut engine, scenario)); + + assert!(string.starts_with("Uncaught \"SyntaxError\": ")); + assert!(string.contains("3:1")); +} + +#[test] +fn test_strict_mode_reserved_name() { + // Checks that usage of a reserved keyword for an identifier name is + // an error in strict mode code as per https://tc39.es/ecma262/#sec-strict-mode-of-ecmascript. + + let mut engine = Context::new(); + + let test_cases = [ + "var implements = 10;", + "var interface = 10;", + "var let = 10;", + "var package = 10;", + "var private = 10;", + "var protected = 10;", + "var public = 10;", + "var static = 10;", + "var yield = 10;", + "var eval = 10;", + "var arguments = 10;", + ]; + + for case in test_cases.iter() { + let scenario = format!("'use strict'; \n {}", case); + + let string = dbg!(forward(&mut engine, &scenario)); + + assert!(string.starts_with("Uncaught \"SyntaxError\": ")); + assert!(string.contains("2:1")); + } +} + +#[test] +fn test_strict_mode_func_decl_in_block() { + // Checks that a function declaration in a block is an error in + // strict mode code. + // TODO - find the spec reference for this. + + let scenario = r#" + 'use strict'; + let a = 4; + let b = 5; + if (a < b) { function f() {} } + "#; + + let mut engine = Context::new(); + + let string = dbg!(forward(&mut engine, scenario)); + + assert!(string.starts_with("Uncaught \"SyntaxError\": ")); + assert!(string.contains("4:1")); +} + +#[test] +fn test_strict_mode_dup_func_parameters() { + // Checks that a function cannot contain duplicate parameter + // names in strict mode code. + + let scenario = r#" + 'use strict'; + function f(a, b, b) {} + "#; + + let mut engine = Context::new(); + + let string = dbg!(forward(&mut engine, scenario)); + + assert!(string.starts_with("Uncaught \"SyntaxError\": ")); + assert!(string.contains("2:1")); +}