Skip to content

Commit

Permalink
Handle non-strict functions in strict functions
Browse files Browse the repository at this point in the history
  • Loading branch information
raskad committed Sep 5, 2021
1 parent b2d9ca8 commit 9b07c85
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 14 deletions.
49 changes: 46 additions & 3 deletions boa/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,14 @@ impl StandardObjects {
}
}

/// Internal representation of the strict mode types.
#[derive(Debug, Copy, Clone)]
pub(crate) enum StrictType {
Off,
Global,
Function,
}

/// Javascript context. It is the primary way to interact with the runtime.
///
/// `Context`s constructed in a thread share the same runtime, therefore it
Expand Down Expand Up @@ -275,7 +283,7 @@ pub struct Context {
pub trace: bool,

/// Whether or not strict mode is active.
pub strict: bool,
strict: StrictType,
}

impl Default for Context {
Expand All @@ -290,7 +298,7 @@ impl Default for Context {
iterator_prototypes: IteratorPrototypes::default(),
standard_objects: Default::default(),
trace: false,
strict: false,
strict: StrictType::Off,
};

// Add new builtIns to Context Realm
Expand Down Expand Up @@ -327,6 +335,36 @@ impl Context {
&mut self.console
}

/// Returns if strict mode is currently active.
#[inline]
pub fn strict(&self) -> bool {
matches!(self.strict, StrictType::Global | StrictType::Function)
}

/// Returns the strict mode type.
#[inline]
pub(crate) fn strict_type(&self) -> StrictType {
self.strict
}

/// Set strict type.
#[inline]
pub(crate) fn set_strict(&mut self, strict: StrictType) {
self.strict = strict;
}

/// Disable the strict mode.
#[inline]
pub fn set_strict_mode_off(&mut self) {
self.strict = StrictType::Off;
}

/// Enable the global strict mode.
#[inline]
pub fn set_strict_mode_global(&mut self) {
self.strict = StrictType::Global;
}

/// Sets up the default global objects within Global
#[inline]
fn create_intrinsics(&mut self) {
Expand Down Expand Up @@ -793,7 +831,12 @@ impl Context {
.map_err(|e| e.to_string());

let execution_result = match parsing_result {
Ok(statement_list) => statement_list.run(self),
Ok(statement_list) => {
if statement_list.strict() {
self.set_strict_mode_global();
}
statement_list.run(self)
}
Err(e) => self.throw_syntax_error(e),
};

Expand Down
2 changes: 1 addition & 1 deletion boa/src/syntax/ast/node/operator/unary_op/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ impl Executable for UnaryOp {
.to_object(context)?
.__delete__(&get_const_field.field().into(), context)?;

if !delete_status && context.strict {
if !delete_status && context.strict() {
return context.throw_type_error("Cannot delete property");
} else {
JsValue::new(delete_status)
Expand Down
23 changes: 17 additions & 6 deletions boa/src/syntax/ast/node/statement_list/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Statement list node.
use crate::{
context::StrictType,
exec::{Executable, InterpreterState},
gc::{empty_trace, Finalize, Trace},
syntax::ast::node::{Declaration, Node},
Expand Down Expand Up @@ -32,12 +33,20 @@ pub struct StatementList {

impl StatementList {
/// Gets the list of items.
#[inline]
pub fn items(&self) -> &[Node] {
&self.items
}

/// Get the strict mode.
#[inline]
pub fn strict(&self) -> bool {
self.strict
}

/// Set the strict mode.
pub fn set_strict_mode(&mut self, strict: bool) {
#[inline]
pub fn set_strict(&mut self, strict: bool) {
self.strict = strict;
}

Expand Down Expand Up @@ -131,17 +140,19 @@ impl Executable for StatementList {
.executor()
.set_current_state(InterpreterState::Executing);

let strict_before = context.strict;
let strict_before = context.strict_type();

if !context.strict && self.strict {
context.strict = true;
match context.strict_type() {
StrictType::Off if self.strict => context.set_strict(StrictType::Function),
StrictType::Function if !self.strict => context.set_strict_mode_off(),
_ => {}
}

for (i, item) in self.items().iter().enumerate() {
let val = match item.run(context) {
Ok(val) => val,
Err(e) => {
context.strict = strict_before;
context.set_strict(strict_before);
return Err(e);
}
};
Expand All @@ -167,7 +178,7 @@ impl Executable for StatementList {
}
}

context.strict = strict_before;
context.set_strict(strict_before);

Ok(obj)
}
Expand Down
22 changes: 22 additions & 0 deletions boa/src/syntax/ast/node/statement_list/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,25 @@ fn strict_mode_global_active_in_function() {

assert_eq!(&exec(scenario), "true");
}

#[test]
fn strict_mode_function_in_function() {
let scenario = r#"
let throws = false;
function a(){
try {
delete Boolean.prototype;
} catch (e) {
throws = true;
}
}
function b(){
'use strict';
a();
}
b();
throws
"#;

assert_eq!(&exec(scenario), "false");
}
2 changes: 1 addition & 1 deletion boa/src/syntax/parser/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ where
cursor.set_strict_mode(global_strict_mode);

let mut statement_list = statement_list?;
statement_list.set_strict_mode(strict);
statement_list.set_strict(strict);
Ok(statement_list)
}
}
2 changes: 1 addition & 1 deletion boa/src/syntax/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ where
_ => {}
}
let mut statement_list = ScriptBody.parse(cursor)?;
statement_list.set_strict_mode(strict);
statement_list.set_strict(strict);
Ok(statement_list)
}
None => Ok(StatementList::from(Vec::new())),
Expand Down
8 changes: 6 additions & 2 deletions boa_tester/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ impl Test {

match self.set_up_env(harness, strict) {
Ok(mut context) => {
context.strict = strict;
if strict {
context.set_strict_mode_global();
}
let res = context.eval(&self.content.as_ref());

let passed = res.is_ok();
Expand Down Expand Up @@ -186,7 +188,9 @@ impl Test {
} else {
match self.set_up_env(harness, strict) {
Ok(mut context) => {
context.strict = strict;
if strict {
context.set_strict_mode_global();
}
match context.eval(&self.content.as_ref()) {
Ok(res) => (false, format!("{}", res.display())),
Err(e) => {
Expand Down

0 comments on commit 9b07c85

Please sign in to comment.