Browse Source

Recognize Directive Prologues correctly (#2521)

This Pull Request changes the following:

- Recognize the `"use strict"` directive prologue correctly.
- Refactor parsers to remove a setter function.
pull/2532/head
raskad 2 years ago
parent
commit
f52d1d3eb5
  1. 18
      boa_ast/src/statement_list.rs
  2. 36
      boa_parser/src/parser/function/mod.rs
  3. 90
      boa_parser/src/parser/mod.rs
  4. 2
      boa_parser/src/parser/statement/block/mod.rs
  5. 12
      boa_parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs
  6. 34
      boa_parser/src/parser/statement/mod.rs
  7. 4
      boa_parser/src/parser/statement/switch/mod.rs

18
boa_ast/src/statement_list.rs

@ -121,6 +121,18 @@ pub struct StatementList {
} }
impl StatementList { impl StatementList {
/// Creates a new `StatementList` AST node.
#[must_use]
pub fn new<S>(statements: S, strict: bool) -> Self
where
S: Into<Box<[StatementListItem]>>,
{
Self {
statements: statements.into(),
strict,
}
}
/// Gets the list of statements. /// Gets the list of statements.
#[inline] #[inline]
#[must_use] #[must_use]
@ -134,12 +146,6 @@ impl StatementList {
pub const fn strict(&self) -> bool { pub const fn strict(&self) -> bool {
self.strict self.strict
} }
/// Set the strict mode.
#[inline]
pub fn set_strict(&mut self, strict: bool) {
self.strict = strict;
}
} }
impl From<Box<[StatementListItem]>> for StatementList { impl From<Box<[StatementListItem]>> for StatementList {

36
boa_parser/src/parser/function/mod.rs

@ -26,7 +26,6 @@ use boa_ast::{
Punctuator, Punctuator,
}; };
use boa_interner::{Interner, Sym}; use boa_interner::{Interner, Sym};
use boa_macros::utf16;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use std::io::Read; use std::io::Read;
@ -449,41 +448,14 @@ where
fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> { fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
let _timer = Profiler::global().start_event("FunctionStatementList", "Parsing"); let _timer = Profiler::global().start_event("FunctionStatementList", "Parsing");
let global_strict_mode = cursor.strict_mode(); StatementList::new(
let mut strict = false;
if let Some(tk) = cursor.peek(0, interner)? {
match tk.kind() {
TokenKind::Punctuator(Punctuator::CloseBlock) => {
return Ok(Vec::new().into());
}
TokenKind::StringLiteral(string)
if interner.resolve_expect(*string).join(
|s| s == "use strict",
|g| g == utf16!("use strict"),
true,
) =>
{
cursor.set_strict_mode(true);
strict = true;
}
_ => {}
}
}
let statement_list = StatementList::new(
self.allow_yield, self.allow_yield,
self.allow_await, self.allow_await,
true, true,
&FUNCTION_BREAK_TOKENS, &FUNCTION_BREAK_TOKENS,
true,
false,
) )
.parse(cursor, interner); .parse(cursor, interner)
// Reset strict mode back to the global scope.
cursor.set_strict_mode(global_strict_mode);
let mut statement_list = statement_list?;
statement_list.set_strict(strict);
Ok(statement_list)
} }
} }

90
boa_parser/src/parser/mod.rs

@ -11,7 +11,6 @@ mod tests;
use crate::{ use crate::{
error::ParseResult, error::ParseResult,
lexer::TokenKind,
parser::{ parser::{
cursor::Cursor, cursor::Cursor,
function::{FormalParameters, FunctionStatementList}, function::{FormalParameters, FunctionStatementList},
@ -27,7 +26,6 @@ use boa_ast::{
Position, StatementList, Position, StatementList,
}; };
use boa_interner::Interner; use boa_interner::Interner;
use boa_macros::utf16;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use std::io::Read; use std::io::Read;
@ -239,52 +237,31 @@ where
type Output = StatementList; type Output = StatementList;
fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> { fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
let mut strict = cursor.strict_mode(); let statement_list = ScriptBody::new(true, cursor.strict_mode(), self.direct_eval)
match cursor.peek(0, interner)? { .parse(cursor, interner)?;
Some(tok) => {
match tok.kind() { // It is a Syntax Error if the LexicallyDeclaredNames of ScriptBody contains any duplicate entries.
// Set the strict mode // It is a Syntax Error if any element of the LexicallyDeclaredNames of ScriptBody also occurs in the VarDeclaredNames of ScriptBody.
TokenKind::StringLiteral(string) let mut lexical_names = FxHashSet::default();
if interner.resolve_expect(*string).join( for name in top_level_lexically_declared_names(&statement_list) {
|s| s == "use strict", if !lexical_names.insert(name) {
|g| g == utf16!("use strict"), return Err(Error::general(
true, "lexical name declared multiple times",
) => Position::new(1, 1),
{ ));
cursor.set_strict_mode(true);
strict = true;
}
_ => {}
}
let mut statement_list =
ScriptBody::new(self.direct_eval).parse(cursor, interner)?;
statement_list.set_strict(strict);
// It is a Syntax Error if the LexicallyDeclaredNames of ScriptBody contains any duplicate entries.
// It is a Syntax Error if any element of the LexicallyDeclaredNames of ScriptBody also occurs in the VarDeclaredNames of ScriptBody.
let mut lexical_names = FxHashSet::default();
for name in top_level_lexically_declared_names(&statement_list) {
if !lexical_names.insert(name) {
return Err(Error::general(
"lexical name declared multiple times",
Position::new(1, 1),
));
}
}
for name in top_level_var_declared_names(&statement_list) {
if lexical_names.contains(&name) {
return Err(Error::general(
"lexical name declared multiple times",
Position::new(1, 1),
));
}
}
Ok(statement_list)
} }
None => Ok(StatementList::from(Vec::new())),
} }
for name in top_level_var_declared_names(&statement_list) {
if lexical_names.contains(&name) {
return Err(Error::general(
"lexical name declared multiple times",
Position::new(1, 1),
));
}
}
Ok(statement_list)
} }
} }
@ -296,14 +273,20 @@ where
/// [spec]: https://tc39.es/ecma262/#prod-ScriptBody /// [spec]: https://tc39.es/ecma262/#prod-ScriptBody
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct ScriptBody { pub struct ScriptBody {
directive_prologues: bool,
strict: bool,
direct_eval: bool, direct_eval: bool,
} }
impl ScriptBody { impl ScriptBody {
/// Create a new `ScriptBody` parser. /// Create a new `ScriptBody` parser.
#[inline] #[inline]
const fn new(direct_eval: bool) -> Self { const fn new(directive_prologues: bool, strict: bool, direct_eval: bool) -> Self {
Self { direct_eval } Self {
directive_prologues,
strict,
direct_eval,
}
} }
} }
@ -314,8 +297,15 @@ where
type Output = StatementList; type Output = StatementList;
fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> { fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
let body = self::statement::StatementList::new(false, false, false, &[]) let body = self::statement::StatementList::new(
.parse(cursor, interner)?; false,
false,
false,
&[],
self.directive_prologues,
self.strict,
)
.parse(cursor, interner)?;
if !self.direct_eval { if !self.direct_eval {
// It is a Syntax Error if StatementList Contains super unless the source text containing super is eval // It is a Syntax Error if StatementList Contains super unless the source text containing super is eval

2
boa_parser/src/parser/statement/block/mod.rs

@ -90,6 +90,8 @@ where
self.allow_await, self.allow_await,
self.allow_return, self.allow_return,
&BLOCK_BREAK_TOKENS, &BLOCK_BREAK_TOKENS,
false,
false,
) )
.parse(cursor, interner) .parse(cursor, interner)
.map(statement::Block::from)?; .map(statement::Block::from)?;

12
boa_parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs

@ -666,9 +666,15 @@ where
let strict = cursor.strict_mode(); let strict = cursor.strict_mode();
cursor.set_strict_mode(true); cursor.set_strict_mode(true);
let position = cursor.peek(0, interner).or_abrupt()?.span().start(); let position = cursor.peek(0, interner).or_abrupt()?.span().start();
let statement_list = let statement_list = StatementList::new(
StatementList::new(false, true, false, &FUNCTION_BREAK_TOKENS) false,
.parse(cursor, interner)?; true,
false,
&FUNCTION_BREAK_TOKENS,
false,
false,
)
.parse(cursor, interner)?;
let mut lexical_names = FxHashSet::default(); let mut lexical_names = FxHashSet::default();
for name in &lexically_declared_names(&statement_list) { for name in &lexically_declared_names(&statement_list) {

34
boa_parser/src/parser/statement/mod.rs

@ -50,6 +50,7 @@ use boa_ast::{
Keyword, Punctuator, Keyword, Punctuator,
}; };
use boa_interner::Interner; use boa_interner::Interner;
use boa_macros::utf16;
use boa_profiler::Profiler; use boa_profiler::Profiler;
use std::io::Read; use std::io::Read;
@ -228,6 +229,8 @@ pub(super) struct StatementList {
allow_await: AllowAwait, allow_await: AllowAwait,
allow_return: AllowReturn, allow_return: AllowReturn,
break_nodes: &'static [TokenKind], break_nodes: &'static [TokenKind],
directive_prologues: bool,
strict: bool,
} }
impl StatementList { impl StatementList {
@ -237,6 +240,8 @@ impl StatementList {
allow_await: A, allow_await: A,
allow_return: R, allow_return: R,
break_nodes: &'static [TokenKind], break_nodes: &'static [TokenKind],
directive_prologues: bool,
strict: bool,
) -> Self ) -> Self
where where
Y: Into<AllowYield>, Y: Into<AllowYield>,
@ -248,6 +253,8 @@ impl StatementList {
allow_await: allow_await.into(), allow_await: allow_await.into(),
allow_return: allow_return.into(), allow_return: allow_return.into(),
break_nodes, break_nodes,
directive_prologues,
strict,
} }
} }
} }
@ -272,6 +279,10 @@ where
let _timer = Profiler::global().start_event("StatementList", "Parsing"); let _timer = Profiler::global().start_event("StatementList", "Parsing");
let mut items = Vec::new(); let mut items = Vec::new();
let global_strict = cursor.strict_mode();
let mut directive_prologues = self.directive_prologues;
let mut strict = self.strict;
loop { loop {
match cursor.peek(0, interner)? { match cursor.peek(0, interner)? {
Some(token) if self.break_nodes.contains(token.kind()) => break, Some(token) if self.break_nodes.contains(token.kind()) => break,
@ -282,6 +293,25 @@ where
let item = let item =
StatementListItem::new(self.allow_yield, self.allow_await, self.allow_return) StatementListItem::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor, interner)?; .parse(cursor, interner)?;
if directive_prologues {
if let ast::StatementListItem::Statement(ast::Statement::Expression(
ast::Expression::Literal(ast::expression::literal::Literal::String(string)),
)) = &item
{
if interner.resolve_expect(*string).join(
|s| s == "use strict",
|g| g == utf16!("use strict"),
true,
) {
cursor.set_strict_mode(true);
strict = true;
}
} else {
directive_prologues = false;
}
}
items.push(item); items.push(item);
// move the cursor forward for any consecutive semicolon. // move the cursor forward for any consecutive semicolon.
@ -290,7 +320,9 @@ where
items.sort_by(ast::StatementListItem::hoistable_order); items.sort_by(ast::StatementListItem::hoistable_order);
Ok(items.into()) cursor.set_strict_mode(global_strict);
Ok(ast::StatementList::new(items, strict))
} }
} }

4
boa_parser/src/parser/statement/switch/mod.rs

@ -173,6 +173,8 @@ where
self.allow_await, self.allow_await,
self.allow_return, self.allow_return,
&CASE_BREAK_TOKENS, &CASE_BREAK_TOKENS,
false,
false,
) )
.parse(cursor, interner)?; .parse(cursor, interner)?;
@ -195,6 +197,8 @@ where
self.allow_await, self.allow_await,
self.allow_return, self.allow_return,
&CASE_BREAK_TOKENS, &CASE_BREAK_TOKENS,
false,
false,
) )
.parse(cursor, interner)?; .parse(cursor, interner)?;

Loading…
Cancel
Save