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 {
/// 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.
#[inline]
#[must_use]
@ -134,12 +146,6 @@ impl StatementList {
pub const fn strict(&self) -> bool {
self.strict
}
/// Set the strict mode.
#[inline]
pub fn set_strict(&mut self, strict: bool) {
self.strict = strict;
}
}
impl From<Box<[StatementListItem]>> for StatementList {

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

@ -26,7 +26,6 @@ use boa_ast::{
Punctuator,
};
use boa_interner::{Interner, Sym};
use boa_macros::utf16;
use boa_profiler::Profiler;
use std::io::Read;
@ -449,41 +448,14 @@ where
fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
let _timer = Profiler::global().start_event("FunctionStatementList", "Parsing");
let global_strict_mode = cursor.strict_mode();
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(
StatementList::new(
self.allow_yield,
self.allow_await,
true,
&FUNCTION_BREAK_TOKENS,
true,
false,
)
.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)
.parse(cursor, interner)
}
}

90
boa_parser/src/parser/mod.rs

@ -11,7 +11,6 @@ mod tests;
use crate::{
error::ParseResult,
lexer::TokenKind,
parser::{
cursor::Cursor,
function::{FormalParameters, FunctionStatementList},
@ -27,7 +26,6 @@ use boa_ast::{
Position, StatementList,
};
use boa_interner::Interner;
use boa_macros::utf16;
use rustc_hash::FxHashSet;
use std::io::Read;
@ -239,52 +237,31 @@ where
type Output = StatementList;
fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
let mut strict = cursor.strict_mode();
match cursor.peek(0, interner)? {
Some(tok) => {
match tok.kind() {
// Set the strict mode
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 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)
let statement_list = ScriptBody::new(true, cursor.strict_mode(), self.direct_eval)
.parse(cursor, interner)?;
// 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),
));
}
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
#[derive(Debug, Clone, Copy)]
pub struct ScriptBody {
directive_prologues: bool,
strict: bool,
direct_eval: bool,
}
impl ScriptBody {
/// Create a new `ScriptBody` parser.
#[inline]
const fn new(direct_eval: bool) -> Self {
Self { direct_eval }
const fn new(directive_prologues: bool, strict: bool, direct_eval: bool) -> Self {
Self {
directive_prologues,
strict,
direct_eval,
}
}
}
@ -314,8 +297,15 @@ where
type Output = StatementList;
fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
let body = self::statement::StatementList::new(false, false, false, &[])
.parse(cursor, interner)?;
let body = self::statement::StatementList::new(
false,
false,
false,
&[],
self.directive_prologues,
self.strict,
)
.parse(cursor, interner)?;
if !self.direct_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_return,
&BLOCK_BREAK_TOKENS,
false,
false,
)
.parse(cursor, interner)
.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();
cursor.set_strict_mode(true);
let position = cursor.peek(0, interner).or_abrupt()?.span().start();
let statement_list =
StatementList::new(false, true, false, &FUNCTION_BREAK_TOKENS)
.parse(cursor, interner)?;
let statement_list = StatementList::new(
false,
true,
false,
&FUNCTION_BREAK_TOKENS,
false,
false,
)
.parse(cursor, interner)?;
let mut lexical_names = FxHashSet::default();
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,
};
use boa_interner::Interner;
use boa_macros::utf16;
use boa_profiler::Profiler;
use std::io::Read;
@ -228,6 +229,8 @@ pub(super) struct StatementList {
allow_await: AllowAwait,
allow_return: AllowReturn,
break_nodes: &'static [TokenKind],
directive_prologues: bool,
strict: bool,
}
impl StatementList {
@ -237,6 +240,8 @@ impl StatementList {
allow_await: A,
allow_return: R,
break_nodes: &'static [TokenKind],
directive_prologues: bool,
strict: bool,
) -> Self
where
Y: Into<AllowYield>,
@ -248,6 +253,8 @@ impl StatementList {
allow_await: allow_await.into(),
allow_return: allow_return.into(),
break_nodes,
directive_prologues,
strict,
}
}
}
@ -272,6 +279,10 @@ where
let _timer = Profiler::global().start_event("StatementList", "Parsing");
let mut items = Vec::new();
let global_strict = cursor.strict_mode();
let mut directive_prologues = self.directive_prologues;
let mut strict = self.strict;
loop {
match cursor.peek(0, interner)? {
Some(token) if self.break_nodes.contains(token.kind()) => break,
@ -282,6 +293,25 @@ where
let item =
StatementListItem::new(self.allow_yield, self.allow_await, self.allow_return)
.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);
// move the cursor forward for any consecutive semicolon.
@ -290,7 +320,9 @@ where
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_return,
&CASE_BREAK_TOKENS,
false,
false,
)
.parse(cursor, interner)?;
@ -195,6 +197,8 @@ where
self.allow_await,
self.allow_return,
&CASE_BREAK_TOKENS,
false,
false,
)
.parse(cursor, interner)?;

Loading…
Cancel
Save