From 51215a822ca0bd308e627b3d61e8d62796c94690 Mon Sep 17 00:00:00 2001 From: tofpie Date: Sun, 17 Jan 2021 14:31:13 +0100 Subject: [PATCH 1/4] Fix internal methods --- boa/examples/classes.rs | 5 +- boa/src/builtins/array/array_iterator.rs | 4 +- boa/src/builtins/array/mod.rs | 100 ++--- boa/src/builtins/array/tests.rs | 2 +- boa/src/builtins/bigint/conversions.rs | 2 +- boa/src/builtins/bigint/mod.rs | 16 +- boa/src/builtins/bigint/tests.rs | 2 +- boa/src/builtins/boolean/mod.rs | 10 +- boa/src/builtins/console/mod.rs | 115 +++--- boa/src/builtins/date/mod.rs | 22 +- boa/src/builtins/date/tests.rs | 7 +- boa/src/builtins/error/eval.rs | 6 +- boa/src/builtins/error/mod.rs | 6 +- boa/src/builtins/error/range.rs | 6 +- boa/src/builtins/error/reference.rs | 11 +- boa/src/builtins/error/syntax.rs | 6 +- boa/src/builtins/error/type.rs | 6 +- boa/src/builtins/error/uri.rs | 6 +- boa/src/builtins/function/mod.rs | 53 +-- boa/src/builtins/global_this/mod.rs | 2 +- boa/src/builtins/infinity/mod.rs | 2 +- boa/src/builtins/iterable/mod.rs | 10 +- boa/src/builtins/json/mod.rs | 11 +- boa/src/builtins/map/map_iterator.rs | 4 +- boa/src/builtins/map/mod.rs | 24 +- boa/src/builtins/math/mod.rs | 72 ++-- boa/src/builtins/mod.rs | 4 +- boa/src/builtins/nan/mod.rs | 2 +- boa/src/builtins/number/mod.rs | 54 +-- boa/src/builtins/object/for_in_iterator.rs | 8 +- boa/src/builtins/object/mod.rs | 40 +- boa/src/builtins/regexp/mod.rs | 38 +- boa/src/builtins/string/mod.rs | 76 ++-- boa/src/builtins/string/string_iterator.rs | 6 +- boa/src/builtins/symbol/mod.rs | 8 +- boa/src/builtins/symbol/tests.rs | 2 +- boa/src/builtins/undefined/mod.rs | 2 +- boa/src/class.rs | 12 +- boa/src/context.rs | 162 ++++---- .../declarative_environment_record.rs | 87 +++-- .../environment/environment_record_trait.rs | 32 +- .../function_environment_record.rs | 77 ++-- .../environment/global_environment_record.rs | 151 ++++---- boa/src/environment/lexical_environment.rs | 183 +++++---- boa/src/environment/mod.rs | 34 +- .../environment/object_environment_record.rs | 54 +-- boa/src/exec/mod.rs | 2 +- boa/src/lib.rs | 18 +- boa/src/object/gcobject.rs | 119 +++--- boa/src/object/internal_methods.rs | 366 ++++++++++++++---- boa/src/object/mod.rs | 16 +- boa/src/realm.rs | 5 +- boa/src/syntax/ast/node/array/mod.rs | 2 +- boa/src/syntax/ast/node/await_expr/mod.rs | 2 +- boa/src/syntax/ast/node/block/mod.rs | 13 +- boa/src/syntax/ast/node/break_node/mod.rs | 3 +- boa/src/syntax/ast/node/break_node/tests.rs | 2 +- boa/src/syntax/ast/node/call/mod.rs | 3 +- .../node/conditional/conditional_op/mod.rs | 2 +- .../ast/node/conditional/if_node/mod.rs | 2 +- .../declaration/arrow_function_decl/mod.rs | 2 +- .../declaration/async_function_decl/mod.rs | 2 +- .../declaration/async_function_expr/mod.rs | 2 +- .../node/declaration/const_decl_list/mod.rs | 19 +- .../ast/node/declaration/function_decl/mod.rs | 26 +- .../ast/node/declaration/function_expr/mod.rs | 2 +- .../ast/node/declaration/let_decl_list/mod.rs | 19 +- .../ast/node/declaration/var_decl_list/mod.rs | 24 +- .../ast/node/field/get_const_field/mod.rs | 2 +- .../syntax/ast/node/field/get_field/mod.rs | 2 +- boa/src/syntax/ast/node/identifier/mod.rs | 6 +- .../ast/node/iteration/continue_node/mod.rs | 3 +- .../ast/node/iteration/do_while_loop/mod.rs | 9 +- .../ast/node/iteration/for_in_loop/mod.rs | 126 +++--- .../syntax/ast/node/iteration/for_loop/mod.rs | 44 +-- .../ast/node/iteration/for_of_loop/mod.rs | 125 +++--- boa/src/syntax/ast/node/iteration/mod.rs | 4 +- .../ast/node/iteration/while_loop/mod.rs | 9 +- boa/src/syntax/ast/node/mod.rs | 6 +- boa/src/syntax/ast/node/new/mod.rs | 2 +- boa/src/syntax/ast/node/object/mod.rs | 6 +- .../syntax/ast/node/operator/assign/mod.rs | 28 +- .../syntax/ast/node/operator/bin_op/mod.rs | 22 +- .../syntax/ast/node/operator/unary_op/mod.rs | 6 +- boa/src/syntax/ast/node/return_smt/mod.rs | 3 +- boa/src/syntax/ast/node/spread/mod.rs | 2 +- boa/src/syntax/ast/node/statement_list/mod.rs | 13 +- boa/src/syntax/ast/node/switch/mod.rs | 23 +- boa/src/syntax/ast/node/template/mod.rs | 4 +- boa/src/syntax/ast/node/throw/mod.rs | 2 +- boa/src/syntax/ast/node/try_node/mod.rs | 19 +- boa/src/value/display.rs | 72 ++-- boa/src/value/equality.rs | 2 +- boa/src/value/mod.rs | 89 +++-- boa/src/value/operations.rs | 38 +- boa/src/value/tests.rs | 27 +- boa/src/vm/mod.rs | 2 +- boa_cli/src/main.rs | 12 +- boa_tester/src/exec.rs | 26 +- boa_wasm/src/lib.rs | 10 +- 100 files changed, 1579 insertions(+), 1358 deletions(-) diff --git a/boa/examples/classes.rs b/boa/examples/classes.rs index 475ce17b5b9..b10468d31db 100644 --- a/boa/examples/classes.rs +++ b/boa/examples/classes.rs @@ -26,7 +26,7 @@ struct Person { // or any function that matches that signature. impl Person { /// This function says hello - fn say_hello(this: &Value, _: &[Value], context: &mut Context) -> Result { + fn say_hello(this: &Value, _: &[Value], context: &Context) -> Result { // We check if this is an object. if let Some(object) = this.as_object() { // If it is we downcast the type to type `Person`. @@ -57,7 +57,8 @@ impl Class for Person { const LENGTH: usize = 2; // This is what is called when we do `new Person()` - fn constructor(_this: &Value, args: &[Value], context: &mut Context) -> Result { + + fn constructor(_this: &Value, args: &[Value], context: &Context) -> Result { // We get the first argument. If it is unavailable we get `undefined`. And, then call `to_string()`. // // This is equivalent to `String(arg)`. diff --git a/boa/src/builtins/array/array_iterator.rs b/boa/src/builtins/array/array_iterator.rs index 729f012b933..0256f754826 100644 --- a/boa/src/builtins/array/array_iterator.rs +++ b/boa/src/builtins/array/array_iterator.rs @@ -67,7 +67,7 @@ impl ArrayIterator { /// - [ECMA reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next - pub(crate) fn next(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn next(this: &Value, _: &[Value], context: &Context) -> Result { if let Value::Object(ref object) = this { let mut object = object.borrow_mut(); if let Some(array_iterator) = object.as_array_iterator_mut() { @@ -118,7 +118,7 @@ impl ArrayIterator { /// - [ECMA reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-%arrayiteratorprototype%-object - pub(crate) fn create_prototype(context: &mut Context, iterator_prototype: Value) -> Value { + pub(crate) fn create_prototype(context: &Context, iterator_prototype: Value) -> Value { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); // Create prototype diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 32b734ff072..1f49383fd4b 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -39,7 +39,7 @@ impl BuiltIn for Array { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let symbol_iterator = context.well_known_symbols().iterator_symbol(); @@ -108,7 +108,7 @@ impl BuiltIn for Array { impl Array { const LENGTH: usize = 1; - fn constructor(new_target: &Value, args: &[Value], context: &mut Context) -> Result { + fn constructor(new_target: &Value, args: &[Value], context: &Context) -> Result { let prototype = new_target .as_object() .and_then(|obj| { @@ -132,7 +132,7 @@ impl Array { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-array-constructor-array - fn construct_array_empty(proto: GcObject, context: &mut Context) -> Result { + fn construct_array_empty(proto: GcObject, context: &Context) -> Result { Array::array_create(0, Some(proto), context) } @@ -145,7 +145,7 @@ impl Array { fn construct_array_length( prototype: GcObject, length: &Value, - context: &mut Context, + context: &Context, ) -> Result { let array = Array::array_create(0, Some(prototype), context)?; @@ -171,7 +171,7 @@ impl Array { fn construct_array_values( prototype: GcObject, items: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let items_len = items.len().try_into().map_err(interror_to_value)?; let array = Array::array_create(items_len, Some(prototype), context)?; @@ -189,11 +189,7 @@ impl Array { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-arraycreate - fn array_create( - length: u32, - prototype: Option, - context: &mut Context, - ) -> Result { + fn array_create(length: u32, prototype: Option, context: &Context) -> Result { let prototype = match prototype { Some(prototype) => prototype, None => context.standard_objects().array_object().prototype(), @@ -240,7 +236,7 @@ impl Array { pub(crate) fn construct_array( array_obj: &Value, array_contents: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let array_obj_ptr = array_obj.clone(); @@ -268,7 +264,7 @@ impl Array { pub(crate) fn add_to_array_object( array_ptr: &Value, add_values: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let orig_length = array_ptr.get_field("length", context)?.to_length(context)?; @@ -297,7 +293,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.isarray /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray - pub(crate) fn is_array(_: &Value, args: &[Value], _: &mut Context) -> Result { + pub(crate) fn is_array(_: &Value, args: &[Value], _: &Context) -> Result { match args.get(0).and_then(|x| x.as_object()) { Some(object) => Ok(Value::from(object.borrow().is_array())), None => Ok(Value::from(false)), @@ -316,7 +312,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.concat /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat - pub(crate) fn concat(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn concat(this: &Value, args: &[Value], context: &Context) -> Result { if args.is_empty() { // If concat is called with no arguments, it returns the original array return Ok(this.clone()); @@ -355,7 +351,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.push /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push - pub(crate) fn push(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn push(this: &Value, args: &[Value], context: &Context) -> Result { let new_array = Self::add_to_array_object(this, args, context)?; Ok(new_array.get_field("length", context)?) } @@ -370,7 +366,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.pop /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop - pub(crate) fn pop(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn pop(this: &Value, _: &[Value], context: &Context) -> Result { let curr_length = this.get_field("length", context)?.to_length(context)?; if curr_length < 1 { @@ -393,7 +389,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.foreach /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach - pub(crate) fn for_each(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn for_each(this: &Value, args: &[Value], context: &Context) -> Result { if args.is_empty() { return Err(Value::from("Missing argument for Array.prototype.forEach")); } @@ -425,7 +421,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.join /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join - pub(crate) fn join(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn join(this: &Value, args: &[Value], context: &Context) -> Result { let separator = if args.is_empty() { String::from(",") } else { @@ -458,7 +454,7 @@ impl Array { /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_string(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_string(this: &Value, _: &[Value], context: &Context) -> Result { let method_name = "join"; let mut arguments = vec![Value::from(",")]; // 2. @@ -498,7 +494,7 @@ impl Array { /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.reverse /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse #[allow(clippy::else_if_without_else)] - pub(crate) fn reverse(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn reverse(this: &Value, _: &[Value], context: &Context) -> Result { let len = this.get_field("length", context)?.to_length(context)?; let middle = len.wrapping_div(2); @@ -506,8 +502,8 @@ impl Array { for lower in 0..middle { let upper = len.wrapping_sub(lower).wrapping_sub(1); - let upper_exists = this.has_field(upper); - let lower_exists = this.has_field(lower); + let upper_exists = this.has_field(upper, context)?; + let lower_exists = this.has_field(lower, context)?; let upper_value = this.get_field(upper, context)?; let lower_value = this.get_field(lower, context)?; @@ -537,7 +533,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.shift /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift - pub(crate) fn shift(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn shift(this: &Value, _: &[Value], context: &Context) -> Result { let len = this.get_field("length", context)?.to_length(context)?; if len == 0 { @@ -578,7 +574,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.unshift /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift - pub(crate) fn unshift(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn unshift(this: &Value, args: &[Value], context: &Context) -> Result { let len = this.get_field("length", context)?.to_length(context)?; let arg_c = args.len(); @@ -624,7 +620,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.every /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every - pub(crate) fn every(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn every(this: &Value, args: &[Value], context: &Context) -> Result { if args.is_empty() { return Err(Value::from( "missing callback when calling function Array.prototype.every", @@ -666,7 +662,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.map /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map - pub(crate) fn map(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn map(this: &Value, args: &[Value], context: &Context) -> Result { if args.is_empty() { return Err(Value::from( "missing argument 0 when calling function Array.prototype.map", @@ -715,7 +711,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.indexof /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf - pub(crate) fn index_of(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn index_of(this: &Value, args: &[Value], context: &Context) -> Result { // If no arguments, return -1. Not described in spec, but is what chrome does. if args.is_empty() { return Ok(Value::from(-1)); @@ -772,11 +768,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.lastindexof /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf - pub(crate) fn last_index_of( - this: &Value, - args: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn last_index_of(this: &Value, args: &[Value], context: &Context) -> Result { // If no arguments, return -1. Not described in spec, but is what chrome does. if args.is_empty() { return Ok(Value::from(-1)); @@ -829,7 +821,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.find /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find - pub(crate) fn find(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn find(this: &Value, args: &[Value], context: &Context) -> Result { if args.is_empty() { return Err(Value::from( "missing callback when calling function Array.prototype.find", @@ -861,7 +853,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.findindex /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex - pub(crate) fn find_index(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn find_index(this: &Value, args: &[Value], context: &Context) -> Result { if args.is_empty() { return Err(Value::from( "Missing argument for Array.prototype.findIndex", @@ -900,7 +892,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.fill /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill - pub(crate) fn fill(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn fill(this: &Value, args: &[Value], context: &Context) -> Result { let len = this.get_field("length", context)?.to_length(context)?; let default_value = Value::undefined(); @@ -925,11 +917,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.includes /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes - pub(crate) fn includes_value( - this: &Value, - args: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn includes_value(this: &Value, args: &[Value], context: &Context) -> Result { let search_element = args.get(0).cloned().unwrap_or_else(Value::undefined); let length = this.get_field("length", context)?.to_length(context)?; @@ -959,7 +947,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.slice /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice - pub(crate) fn slice(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn slice(this: &Value, args: &[Value], context: &Context) -> Result { let new_array = Self::new_array(context)?; let len = this.get_field("length", context)?.to_length(context)?; @@ -993,7 +981,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.filter /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter - pub(crate) fn filter(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn filter(this: &Value, args: &[Value], context: &Context) -> Result { if args.is_empty() { return Err(Value::from( "missing argument 0 when calling function Array.prototype.filter", @@ -1042,7 +1030,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.some /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some - pub(crate) fn some(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn some(this: &Value, args: &[Value], context: &Context) -> Result { if args.is_empty() { return Err(Value::from( "missing callback when calling function Array.prototype.some", @@ -1085,7 +1073,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.reduce /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce - pub(crate) fn reduce(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn reduce(this: &Value, args: &[Value], context: &Context) -> Result { let this: Value = this.to_object(context)?.into(); let callback = match args.get(0) { Some(value) if value.is_function() => value, @@ -1101,7 +1089,7 @@ impl Array { let mut accumulator = if initial_value.is_undefined() { let mut k_present = false; while k < length { - if this.has_field(k) { + if this.has_field(k, context)? { k_present = true; break; } @@ -1119,7 +1107,7 @@ impl Array { initial_value }; while k < length { - if this.has_field(k) { + if this.has_field(k, context)? { let arguments = [ accumulator, this.get_field(k, context)?, @@ -1151,11 +1139,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.reduceright /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight - pub(crate) fn reduce_right( - this: &Value, - args: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn reduce_right(this: &Value, args: &[Value], context: &Context) -> Result { let this: Value = this.to_object(context)?.into(); let callback = match args.get(0) { Some(value) if value.is_function() => value, @@ -1177,7 +1161,7 @@ impl Array { let mut accumulator = if initial_value.is_undefined() { let mut k_present = false; loop { - if this.has_field(k) { + if this.has_field(k, context)? { k_present = true; break; } @@ -1200,7 +1184,7 @@ impl Array { }; // usize::MAX is bigger than the maximum array size so we can use it check for integer undeflow while k != usize::MAX { - if this.has_field(k) { + if this.has_field(k, context)? { let arguments = [ accumulator, this.get_field(k, context)?, @@ -1244,7 +1228,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.values /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values - pub(crate) fn values(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn values(this: &Value, _: &[Value], context: &Context) -> Result { ArrayIterator::create_array_iterator(context, this.clone(), ArrayIterationKind::Value) } @@ -1258,7 +1242,7 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.values /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values - pub(crate) fn keys(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn keys(this: &Value, _: &[Value], context: &Context) -> Result { ArrayIterator::create_array_iterator(context, this.clone(), ArrayIterationKind::Key) } @@ -1272,13 +1256,13 @@ impl Array { /// /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.values /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values - pub(crate) fn entries(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn entries(this: &Value, _: &[Value], context: &Context) -> Result { ArrayIterator::create_array_iterator(context, this.clone(), ArrayIterationKind::KeyAndValue) } /// Represents the algorithm to calculate `relativeStart` (or `k`) in array functions. pub(super) fn get_relative_start( - context: &mut Context, + context: &Context, arg: Option<&Value>, len: usize, ) -> Result { @@ -1308,7 +1292,7 @@ impl Array { /// Represents the algorithm to calculate `relativeEnd` (or `final`) in array functions. pub(super) fn get_relative_end( - context: &mut Context, + context: &Context, arg: Option<&Value>, len: usize, ) -> Result { diff --git a/boa/src/builtins/array/tests.rs b/boa/src/builtins/array/tests.rs index dac5b842b40..61df606c057 100644 --- a/boa/src/builtins/array/tests.rs +++ b/boa/src/builtins/array/tests.rs @@ -1367,6 +1367,6 @@ fn array_length_is_not_enumerable() { let context = Context::new(); let array = Array::new_array(&context).unwrap(); - let desc = array.get_property("length").unwrap(); + let desc = array.get_property("length", &context).unwrap().unwrap(); assert!(!desc.enumerable()); } diff --git a/boa/src/builtins/bigint/conversions.rs b/boa/src/builtins/bigint/conversions.rs index 6cdb1f14f20..f5ae5a4dc1e 100644 --- a/boa/src/builtins/bigint/conversions.rs +++ b/boa/src/builtins/bigint/conversions.rs @@ -14,7 +14,7 @@ impl BigInt { /// /// [spec]: https://tc39.es/ecma262/#sec-stringtobigint #[inline] - pub(crate) fn from_string(string: &str, context: &mut Context) -> Result { + pub(crate) fn from_string(string: &str, context: &Context) -> Result { if string.trim().is_empty() { return Ok(BigInt::from(0)); } diff --git a/boa/src/builtins/bigint/mod.rs b/boa/src/builtins/bigint/mod.rs index b5a80f40fac..0adf21bd8d0 100644 --- a/boa/src/builtins/bigint/mod.rs +++ b/boa/src/builtins/bigint/mod.rs @@ -47,7 +47,7 @@ impl BuiltIn for BigInt { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let bigint_object = ConstructorBuilder::with_standard_object( @@ -83,7 +83,7 @@ impl BigInt { /// /// [spec]: https://tc39.es/ecma262/#sec-bigint-objects /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt - fn constructor(_: &Value, args: &[Value], context: &mut Context) -> Result { + fn constructor(_: &Value, args: &[Value], context: &Context) -> Result { let data = match args.get(0) { Some(ref value) => value.to_bigint(context)?, None => RcBigInt::from(Self::from(0)), @@ -102,7 +102,7 @@ impl BigInt { /// /// [spec]: https://tc39.es/ecma262/#sec-thisbigintvalue #[inline] - fn this_bigint_value(value: &Value, context: &mut Context) -> Result { + fn this_bigint_value(value: &Value, context: &Context) -> Result { match value { // 1. If Type(value) is BigInt, return value. Value::BigInt(ref bigint) => return Ok(bigint.clone()), @@ -133,7 +133,7 @@ impl BigInt { /// [spec]: https://tc39.es/ecma262/#sec-bigint.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toString #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_string(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_string(this: &Value, args: &[Value], context: &Context) -> Result { let radix = if !args.is_empty() { args[0].to_integer(context)? as i32 } else { @@ -158,7 +158,7 @@ impl BigInt { /// /// [spec]: https://tc39.es/ecma262/#sec-bigint.prototype.valueof /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/valueOf - pub(crate) fn value_of(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn value_of(this: &Value, _: &[Value], context: &Context) -> Result { Ok(Value::from(Self::this_bigint_value(this, context)?)) } @@ -169,7 +169,7 @@ impl BigInt { /// [spec]: https://tc39.es/ecma262/#sec-bigint.asintn /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/asIntN #[allow(clippy::wrong_self_convention)] - pub(crate) fn as_int_n(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn as_int_n(_: &Value, args: &[Value], context: &Context) -> Result { let (modulo, bits) = Self::calculate_as_uint_n(args, context)?; if bits > 0 @@ -196,7 +196,7 @@ impl BigInt { /// [spec]: https://tc39.es/ecma262/#sec-bigint.asuintn /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/asUintN #[allow(clippy::wrong_self_convention)] - pub(crate) fn as_uint_n(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn as_uint_n(_: &Value, args: &[Value], context: &Context) -> Result { let (modulo, _) = Self::calculate_as_uint_n(args, context)?; Ok(Value::from(modulo)) @@ -207,7 +207,7 @@ impl BigInt { /// This function expects the same arguments as `as_uint_n` and wraps the value of a `BigInt`. /// Additionally to the wrapped unsigned value it returns the converted `bits` argument, so it /// can be reused from the `as_int_n` method. - fn calculate_as_uint_n(args: &[Value], context: &mut Context) -> Result<(BigInt, u32)> { + fn calculate_as_uint_n(args: &[Value], context: &Context) -> Result<(BigInt, u32)> { use std::convert::TryFrom; let undefined_value = Value::undefined(); diff --git a/boa/src/builtins/bigint/tests.rs b/boa/src/builtins/bigint/tests.rs index 0caf9b2ddf7..b30182de1fd 100644 --- a/boa/src/builtins/bigint/tests.rs +++ b/boa/src/builtins/bigint/tests.rs @@ -395,7 +395,7 @@ fn as_uint_n_errors() { assert_throws(&mut context, "BigInt.asUintN(0n, 0n)", "TypeError"); } -fn assert_throws(context: &mut Context, src: &str, error_type: &str) { +fn assert_throws(context: &Context, src: &str, error_type: &str) { let result = forward(context, src); assert!(result.contains(error_type)); } diff --git a/boa/src/builtins/boolean/mod.rs b/boa/src/builtins/boolean/mod.rs index 4c8f1b67c62..91ec8fcc32f 100644 --- a/boa/src/builtins/boolean/mod.rs +++ b/boa/src/builtins/boolean/mod.rs @@ -31,7 +31,7 @@ impl BuiltIn for Boolean { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let boolean_object = ConstructorBuilder::with_standard_object( @@ -59,7 +59,7 @@ impl Boolean { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { // Get the argument, if any let data = args.get(0).map(|x| x.to_boolean()).unwrap_or(false); @@ -92,7 +92,7 @@ impl Boolean { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-thisbooleanvalue - fn this_boolean_value(value: &Value, context: &mut Context) -> Result { + fn this_boolean_value(value: &Value, context: &Context) -> Result { match value { Value::Boolean(boolean) => return Ok(*boolean), Value::Object(ref object) => { @@ -116,7 +116,7 @@ impl Boolean { /// [spec]: https://tc39.es/ecma262/#sec-boolean-object /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/toString #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_string(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_string(this: &Value, _: &[Value], context: &Context) -> Result { let boolean = Self::this_boolean_value(this, context)?; Ok(Value::from(boolean.to_string())) } @@ -130,7 +130,7 @@ impl Boolean { /// [spec]: https://tc39.es/ecma262/#sec-boolean.prototype.valueof /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/valueOf #[inline] - pub(crate) fn value_of(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn value_of(this: &Value, _: &[Value], context: &Context) -> Result { Ok(Value::from(Self::this_boolean_value(this, context)?)) } } diff --git a/boa/src/builtins/console/mod.rs b/boa/src/builtins/console/mod.rs index e96beebe09c..dcdc1f8d5b0 100644 --- a/boa/src/builtins/console/mod.rs +++ b/boa/src/builtins/console/mod.rs @@ -58,7 +58,7 @@ pub(crate) fn logger(msg: LogMessage, console_state: &Console) { } /// This represents the `console` formatter. -pub fn formatter(data: &[Value], context: &mut Context) -> Result { +pub fn formatter(data: &[Value], context: &Context) -> Result { let target = data .get(0) .cloned() @@ -99,7 +99,7 @@ pub fn formatter(data: &[Value], context: &mut Context) -> Result { /* object, FIXME: how to render this properly? */ 'o' | 'O' => { let arg = data.get(arg_index).cloned().unwrap_or_default(); - formatted.push_str(&format!("{}", arg.display())); + formatted.push_str(&format!("{}", arg.display(context))); arg_index += 1 } /* string */ @@ -149,7 +149,7 @@ impl BuiltIn for Console { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let console = ObjectInitializer::new(context) .function(Self::assert, "assert", 0) @@ -192,7 +192,7 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#assert /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/assert - pub(crate) fn assert(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn assert(_: &Value, args: &[Value], context: &Context) -> Result { let assertion = get_arg_at_index::(args, 0).unwrap_or_default(); if !assertion { @@ -203,13 +203,13 @@ impl Console { } else if !args[0].is_string() { args.insert(0, Value::from(message)); } else { - let concat = format!("{}: {}", message, args[0].display()); + let concat = format!("{}: {}", message, args[0].display(context)); args[0] = Value::from(concat); } logger( LogMessage::Error(formatter(&args, context)?), - context.console(), + &context.console().borrow(), ); } @@ -226,8 +226,8 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#clear /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/clear - pub(crate) fn clear(_: &Value, _: &[Value], context: &mut Context) -> Result { - context.console_mut().groups.clear(); + pub(crate) fn clear(_: &Value, _: &[Value], context: &Context) -> Result { + context.console().borrow_mut().groups.clear(); Ok(Value::undefined()) } @@ -241,10 +241,10 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#debug /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/debug - pub(crate) fn debug(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn debug(_: &Value, args: &[Value], context: &Context) -> Result { logger( LogMessage::Log(formatter(args, context)?), - context.console(), + &context.console().borrow(), ); Ok(Value::undefined()) } @@ -259,10 +259,10 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#error /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/error - pub(crate) fn error(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn error(_: &Value, args: &[Value], context: &Context) -> Result { logger( LogMessage::Error(formatter(args, context)?), - context.console(), + &context.console().borrow(), ); Ok(Value::undefined()) } @@ -277,10 +277,10 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#info /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/info - pub(crate) fn info(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn info(_: &Value, args: &[Value], context: &Context) -> Result { logger( LogMessage::Info(formatter(args, context)?), - context.console(), + &context.console().borrow(), ); Ok(Value::undefined()) } @@ -295,10 +295,10 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#log /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/log - pub(crate) fn log(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn log(_: &Value, args: &[Value], context: &Context) -> Result { logger( LogMessage::Log(formatter(args, context)?), - context.console(), + &context.console().borrow(), ); Ok(Value::undefined()) } @@ -313,17 +313,17 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#trace /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/trace - pub(crate) fn trace(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn trace(_: &Value, args: &[Value], context: &Context) -> Result { if !args.is_empty() { logger( LogMessage::Log(formatter(args, context)?), - context.console(), + &context.console().borrow(), ); /* TODO: get and print stack trace */ logger( LogMessage::Log("Not implemented: ".to_string()), - context.console(), + &context.console().borrow(), ) } @@ -340,10 +340,10 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#warn /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/warn - pub(crate) fn warn(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn warn(_: &Value, args: &[Value], context: &Context) -> Result { logger( LogMessage::Warn(formatter(args, context)?), - context.console(), + &context.console().borrow(), ); Ok(Value::undefined()) } @@ -358,20 +358,18 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#count /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/count - pub(crate) fn count(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn count(_: &Value, args: &[Value], context: &Context) -> Result { let label = match args.get(0) { Some(value) => value.to_string(context)?, None => "default".into(), }; let msg = format!("count {}:", &label); - let c = context.console_mut().count_map.entry(label).or_insert(0); + let console = &mut context.console().borrow_mut(); + let c = console.count_map.entry(label).or_insert(0); *c += 1; - logger( - LogMessage::Info(format!("{} {}", msg, c)), - context.console(), - ); + logger(LogMessage::Info(format!("{} {}", msg, c)), &console); Ok(Value::undefined()) } @@ -385,18 +383,16 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#countreset /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/countReset - pub(crate) fn count_reset(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn count_reset(_: &Value, args: &[Value], context: &Context) -> Result { let label = match args.get(0) { Some(value) => value.to_string(context)?, None => "default".into(), }; - context.console_mut().count_map.remove(&label); + let console = &mut context.console().borrow_mut(); + console.count_map.remove(&label); - logger( - LogMessage::Warn(format!("countReset {}", label)), - context.console(), - ); + logger(LogMessage::Warn(format!("countReset {}", label)), &console); Ok(Value::undefined()) } @@ -419,20 +415,20 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#time /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/time - pub(crate) fn time(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn time(_: &Value, args: &[Value], context: &Context) -> Result { let label = match args.get(0) { Some(value) => value.to_string(context)?, None => "default".into(), }; - - if context.console().timer_map.get(&label).is_some() { + let console = &mut context.console().borrow_mut(); + if console.timer_map.get(&label).is_some() { logger( LogMessage::Warn(format!("Timer '{}' already exist", label)), - context.console(), + &console, ); } else { let time = Self::system_time_in_ms(); - context.console_mut().timer_map.insert(label, time); + console.timer_map.insert(label, time); } Ok(Value::undefined()) @@ -448,23 +444,23 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#timelog /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/timeLog - pub(crate) fn time_log(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn time_log(_: &Value, args: &[Value], context: &Context) -> Result { let label = match args.get(0) { Some(value) => value.to_string(context)?, None => "default".into(), }; - - if let Some(t) = context.console().timer_map.get(&label) { + let console = context.console().borrow_mut(); + if let Some(t) = console.timer_map.get(&label) { let time = Self::system_time_in_ms(); let mut concat = format!("{}: {} ms", label, time - t); for msg in args.iter().skip(1) { - concat = concat + " " + &msg.display().to_string(); + concat = concat + " " + &msg.display(context).to_string(); } - logger(LogMessage::Log(concat), context.console()); + logger(LogMessage::Log(concat), &console); } else { logger( LogMessage::Warn(format!("Timer '{}' doesn't exist", label)), - context.console(), + &console, ); } @@ -481,22 +477,23 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#timeend /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/timeEnd - pub(crate) fn time_end(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn time_end(_: &Value, args: &[Value], context: &Context) -> Result { let label = match args.get(0) { Some(value) => value.to_string(context)?, None => "default".into(), }; - if let Some(t) = context.console_mut().timer_map.remove(label.as_str()) { + let console = &mut context.console().borrow_mut(); + if let Some(t) = console.timer_map.remove(label.as_str()) { let time = Self::system_time_in_ms(); logger( LogMessage::Info(format!("{}: {} ms - timer removed", label, time - t)), - context.console(), + &console, ); } else { logger( LogMessage::Warn(format!("Timer '{}' doesn't exist", label)), - context.console(), + &console, ); } @@ -513,14 +510,14 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#group /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/group - pub(crate) fn group(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn group(_: &Value, args: &[Value], context: &Context) -> Result { let group_label = formatter(args, context)?; - + let console = &mut context.console().borrow_mut(); logger( LogMessage::Info(format!("group: {}", &group_label)), - context.console(), + &console, ); - context.console_mut().groups.push(group_label); + console.groups.push(group_label); Ok(Value::undefined()) } @@ -535,8 +532,8 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#groupend /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/groupEnd - pub(crate) fn group_end(_: &Value, _: &[Value], context: &mut Context) -> Result { - context.console_mut().groups.pop(); + pub(crate) fn group_end(_: &Value, _: &[Value], context: &Context) -> Result { + context.console().borrow_mut().groups.pop(); Ok(Value::undefined()) } @@ -551,11 +548,15 @@ impl Console { /// /// [spec]: https://console.spec.whatwg.org/#dir /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/dir - pub(crate) fn dir(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn dir(_: &Value, args: &[Value], context: &Context) -> Result { let undefined = Value::undefined(); logger( - LogMessage::Info(display_obj(args.get(0).unwrap_or(&undefined), true)), - context.console(), + LogMessage::Info(display_obj( + args.get(0).unwrap_or(&undefined), + true, + context, + )), + &context.console().borrow(), ); Ok(Value::undefined()) diff --git a/boa/src/builtins/date/mod.rs b/boa/src/builtins/date/mod.rs index f19a2791ec2..78f3dd23315 100644 --- a/boa/src/builtins/date/mod.rs +++ b/boa/src/builtins/date/mod.rs @@ -38,13 +38,13 @@ fn ignore_ambiguity(result: LocalResult) -> Option { macro_rules! getter_method { ($name:ident) => {{ - fn get_value(this: &Value, _: &[Value], context: &mut Context) -> Result { + fn get_value(this: &Value, _: &[Value], context: &Context) -> Result { Ok(Value::from(this_time_value(this, context)?.$name())) } get_value }}; (Self::$name:ident) => {{ - fn get_value(_: &Value, _: &[Value], _: &mut Context) -> Result { + fn get_value(_: &Value, _: &[Value], _: &Context) -> Result { Ok(Value::from(Date::$name())) } get_value @@ -53,7 +53,7 @@ macro_rules! getter_method { macro_rules! setter_method { ($name:ident($($e:expr),* $(,)?)) => {{ - fn set_value(this: &Value, args: &[Value], context: &mut Context) -> Result { + fn set_value(this: &Value, args: &[Value], context: &Context) -> Result { let mut result = this_time_value(this, context)?; result.$name( $( @@ -112,7 +112,7 @@ impl BuiltIn for Date { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let date_object = ConstructorBuilder::new(context, Self::constructor) @@ -326,7 +326,7 @@ impl Date { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { if new_target.is_undefined() { Self::make_date_string() @@ -396,7 +396,7 @@ impl Date { pub(crate) fn make_date_single( this: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let value = &args[0]; let tv = match this_time_value(value, context) { @@ -433,7 +433,7 @@ impl Date { pub(crate) fn make_date_multiple( this: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let year = args[0].to_number(context)?; let month = args[1].to_number(context)?; @@ -1269,7 +1269,7 @@ impl Date { /// /// [spec]: https://tc39.es/ecma262/#sec-date.now /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now - pub(crate) fn now(_: &Value, _: &[Value], _: &mut Context) -> Result { + pub(crate) fn now(_: &Value, _: &[Value], _: &Context) -> Result { Ok(Value::from(Utc::now().timestamp_millis() as f64)) } @@ -1285,7 +1285,7 @@ impl Date { /// /// [spec]: https://tc39.es/ecma262/#sec-date.parse /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse - pub(crate) fn parse(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn parse(_: &Value, args: &[Value], context: &Context) -> Result { // This method is implementation-defined and discouraged, so we just require the same format as the string // constructor. @@ -1309,7 +1309,7 @@ impl Date { /// /// [spec]: https://tc39.es/ecma262/#sec-date.utc /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC - pub(crate) fn utc(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn utc(_: &Value, args: &[Value], context: &Context) -> Result { let year = args .get(0) .map_or(Ok(f64::NAN), |value| value.to_number(context))?; @@ -1371,7 +1371,7 @@ impl Date { /// /// [spec]: https://tc39.es/ecma262/#sec-thistimevalue #[inline] -pub fn this_time_value(value: &Value, context: &mut Context) -> Result { +pub fn this_time_value(value: &Value, context: &Context) -> Result { if let Value::Object(ref object) = value { if let ObjectData::Date(ref date) = object.borrow().data { return Ok(*date); diff --git a/boa/src/builtins/date/tests.rs b/boa/src/builtins/date/tests.rs index 1071fc564d9..01063443705 100644 --- a/boa/src/builtins/date/tests.rs +++ b/boa/src/builtins/date/tests.rs @@ -6,7 +6,7 @@ use chrono::prelude::*; // NOTE: Javascript Uses 0-based months, where chrono uses 1-based months. Many of the assertions look wrong because of // this. -fn forward_dt_utc(context: &mut Context, src: &str) -> Option { +fn forward_dt_utc(context: &Context, src: &str) -> Option { let date_time = if let Ok(v) = forward_val(context, src) { v } else { @@ -24,7 +24,7 @@ fn forward_dt_utc(context: &mut Context, src: &str) -> Option { } } -fn forward_dt_local(context: &mut Context, src: &str) -> Option { +fn forward_dt_local(context: &Context, src: &str) -> Option { let date_time = forward_dt_utc(context, src); // The timestamp is converted to UTC for internal representation @@ -61,7 +61,8 @@ fn date_this_time_value() { ) .expect_err("Expected error"); let message_property = &error - .get_property("message") + .get_property("message", &context) + .unwrap() .expect("Expected 'message' property") .as_data_descriptor() .unwrap() diff --git a/boa/src/builtins/error/eval.rs b/boa/src/builtins/error/eval.rs index 0e1ccad1a3e..70690ec50e6 100644 --- a/boa/src/builtins/error/eval.rs +++ b/boa/src/builtins/error/eval.rs @@ -31,7 +31,7 @@ impl BuiltIn for EvalError { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let error_prototype = context.standard_objects().error_object().prototype(); @@ -60,7 +60,7 @@ impl EvalError { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let prototype = new_target .as_object() @@ -70,7 +70,7 @@ impl EvalError { .transpose() }) .transpose()? - .unwrap_or_else(|| context.standard_objects().error_object().prototype()); + .unwrap_or_else(|| context.standard_objects().eval_error_object().prototype()); let mut obj = context.construct_object(); obj.set_prototype_instance(prototype.into()); let this = Value::from(obj); diff --git a/boa/src/builtins/error/mod.rs b/boa/src/builtins/error/mod.rs index 60622cfd1b9..d16a2fb956e 100644 --- a/boa/src/builtins/error/mod.rs +++ b/boa/src/builtins/error/mod.rs @@ -46,7 +46,7 @@ impl BuiltIn for Error { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; @@ -76,7 +76,7 @@ impl Error { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let prototype = new_target .as_object() @@ -113,7 +113,7 @@ impl Error { /// [spec]: https://tc39.es/ecma262/#sec-error.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/toString #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_string(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_string(this: &Value, _: &[Value], context: &Context) -> Result { if !this.is_object() { return context.throw_type_error("'this' is not an Object"); } diff --git a/boa/src/builtins/error/range.rs b/boa/src/builtins/error/range.rs index ed020897650..cccca9784c3 100644 --- a/boa/src/builtins/error/range.rs +++ b/boa/src/builtins/error/range.rs @@ -28,7 +28,7 @@ impl BuiltIn for RangeError { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let error_prototype = context.standard_objects().error_object().prototype(); @@ -57,7 +57,7 @@ impl RangeError { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let prototype = new_target .as_object() @@ -67,7 +67,7 @@ impl RangeError { .transpose() }) .transpose()? - .unwrap_or_else(|| context.standard_objects().error_object().prototype()); + .unwrap_or_else(|| context.standard_objects().range_error_object().prototype()); let mut obj = context.construct_object(); obj.set_prototype_instance(prototype.into()); let this = Value::from(obj); diff --git a/boa/src/builtins/error/reference.rs b/boa/src/builtins/error/reference.rs index a1e7153ffb4..a65336e807b 100644 --- a/boa/src/builtins/error/reference.rs +++ b/boa/src/builtins/error/reference.rs @@ -27,7 +27,7 @@ impl BuiltIn for ReferenceError { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let error_prototype = context.standard_objects().error_object().prototype(); @@ -56,7 +56,7 @@ impl ReferenceError { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let prototype = new_target .as_object() @@ -66,7 +66,12 @@ impl ReferenceError { .transpose() }) .transpose()? - .unwrap_or_else(|| context.standard_objects().error_object().prototype()); + .unwrap_or_else(|| { + context + .standard_objects() + .reference_error_object() + .prototype() + }); let mut obj = context.construct_object(); obj.set_prototype_instance(prototype.into()); let this = Value::from(obj); diff --git a/boa/src/builtins/error/syntax.rs b/boa/src/builtins/error/syntax.rs index b5764d219a6..ed1a8653ede 100644 --- a/boa/src/builtins/error/syntax.rs +++ b/boa/src/builtins/error/syntax.rs @@ -30,7 +30,7 @@ impl BuiltIn for SyntaxError { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let error_prototype = context.standard_objects().error_object().prototype(); @@ -59,7 +59,7 @@ impl SyntaxError { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let prototype = new_target .as_object() @@ -69,7 +69,7 @@ impl SyntaxError { .transpose() }) .transpose()? - .unwrap_or_else(|| context.standard_objects().error_object().prototype()); + .unwrap_or_else(|| context.standard_objects().syntax_error_object().prototype()); let mut obj = context.construct_object(); obj.set_prototype_instance(prototype.into()); let this = Value::from(obj); diff --git a/boa/src/builtins/error/type.rs b/boa/src/builtins/error/type.rs index c348d36aeb0..5cca256f1c3 100644 --- a/boa/src/builtins/error/type.rs +++ b/boa/src/builtins/error/type.rs @@ -33,7 +33,7 @@ impl BuiltIn for TypeError { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let error_prototype = context.standard_objects().error_object().prototype(); @@ -62,7 +62,7 @@ impl TypeError { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let prototype = new_target .as_object() @@ -72,7 +72,7 @@ impl TypeError { .transpose() }) .transpose()? - .unwrap_or_else(|| context.standard_objects().error_object().prototype()); + .unwrap_or_else(|| context.standard_objects().type_error_object().prototype()); let mut obj = context.construct_object(); obj.set_prototype_instance(prototype.into()); let this = Value::from(obj); diff --git a/boa/src/builtins/error/uri.rs b/boa/src/builtins/error/uri.rs index 928627c9531..1549a4b010d 100644 --- a/boa/src/builtins/error/uri.rs +++ b/boa/src/builtins/error/uri.rs @@ -29,7 +29,7 @@ impl BuiltIn for UriError { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let error_prototype = context.standard_objects().error_object().prototype(); @@ -58,7 +58,7 @@ impl UriError { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let prototype = new_target .as_object() @@ -68,7 +68,7 @@ impl UriError { .transpose() }) .transpose()? - .unwrap_or_else(|| context.standard_objects().error_object().prototype()); + .unwrap_or_else(|| context.standard_objects().uri_error_object().prototype()); let mut obj = context.construct_object(); obj.set_prototype_instance(prototype.into()); let this = Value::from(obj); diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index 4a07f00855f..5261b90bf87 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -28,7 +28,7 @@ use std::fmt::{self, Debug}; mod tests; /// _fn(this, arguments, context) -> ResultValue_ - The signature of a built-in function -pub type NativeFunction = fn(&Value, &[Value], &mut Context) -> Result; +pub type NativeFunction = fn(&Value, &[Value], &Context) -> Result; #[derive(Clone, Copy, Finalize)] pub struct BuiltInFunction(pub(crate) NativeFunction); @@ -115,9 +115,9 @@ impl Function { param: &FormalParameter, index: usize, args_list: &[Value], - context: &mut Context, + context: &Context, local_env: &Environment, - ) { + ) -> Result<()> { // Create array of values let array = Array::new_array(context).unwrap(); Array::add_to_array_object(&array, &args_list[index..], context).unwrap(); @@ -126,14 +126,12 @@ impl Function { local_env .borrow_mut() // Function parameters can share names in JavaScript... - .create_mutable_binding(param.name().to_owned(), false, true) - .expect("Failed to create binding for rest param"); + .create_mutable_binding(param.name().to_owned(), false, true, context)?; // Set Binding to value local_env .borrow_mut() - .initialize_binding(param.name(), array) - .expect("Failed to initialize rest param"); + .initialize_binding(param.name(), array, context) } // Adds an argument to the environment @@ -142,18 +140,20 @@ impl Function { param: &FormalParameter, value: Value, local_env: &Environment, - ) { + context: &Context, + ) -> Result<()> { // Create binding - local_env - .borrow_mut() - .create_mutable_binding(param.name().to_owned(), false, true) - .expect("Failed to create binding"); + local_env.borrow_mut().create_mutable_binding( + param.name().to_owned(), + false, + true, + context, + )?; // Set Binding to value local_env .borrow_mut() - .initialize_binding(param.name(), value) - .expect("Failed to intialize binding"); + .initialize_binding(param.name(), value, context) } /// Returns true if the function object is callable. @@ -176,7 +176,10 @@ impl Function { /// Arguments. /// /// -pub fn create_unmapped_arguments_object(arguments_list: &[Value]) -> Value { +pub fn create_unmapped_arguments_object( + arguments_list: &[Value], + context: &Context, +) -> Result { let len = arguments_list.len(); let mut obj = GcObject::new(Object::default()); // Set length @@ -185,7 +188,7 @@ pub fn create_unmapped_arguments_object(arguments_list: &[Value]) -> Value { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ); // Define length as a property - obj.ordinary_define_own_property("length", length.into()); + obj.ordinary_define_own_property("length", length.into(), context)?; let mut index: usize = 0; while index < len { let val = arguments_list.get(index).expect("Could not get argument"); @@ -198,7 +201,7 @@ pub fn create_unmapped_arguments_object(arguments_list: &[Value]) -> Value { index += 1; } - Value::from(obj) + Ok(Value::from(obj)) } /// Creates a new member function of a `Object` or `prototype`. @@ -256,7 +259,7 @@ pub struct BuiltInFunctionObject; impl BuiltInFunctionObject { pub const LENGTH: usize = 1; - fn constructor(new_target: &Value, _: &[Value], context: &mut Context) -> Result { + fn constructor(new_target: &Value, _: &[Value], context: &Context) -> Result { let prototype = new_target .as_object() .and_then(|obj| { @@ -279,7 +282,7 @@ impl BuiltInFunctionObject { Ok(this) } - fn prototype(_: &Value, _: &[Value], _: &mut Context) -> Result { + fn prototype(_: &Value, _: &[Value], _: &Context) -> Result { Ok(Value::undefined()) } @@ -293,9 +296,10 @@ impl BuiltInFunctionObject { /// /// [spec]: https://tc39.es/ecma262/#sec-function.prototype.call /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call - fn call(this: &Value, args: &[Value], context: &mut Context) -> Result { + fn call(this: &Value, args: &[Value], context: &Context) -> Result { if !this.is_function() { - return context.throw_type_error(format!("{} is not a function", this.display())); + return context + .throw_type_error(format!("{} is not a function", this.display(context))); } let this_arg: Value = args.get(0).cloned().unwrap_or_default(); // TODO?: 3. Perform PrepareForTailCall @@ -314,9 +318,10 @@ impl BuiltInFunctionObject { /// /// [spec]: https://tc39.es/ecma262/#sec-function.prototype.apply /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply - fn apply(this: &Value, args: &[Value], context: &mut Context) -> Result { + fn apply(this: &Value, args: &[Value], context: &Context) -> Result { if !this.is_function() { - return context.throw_type_error(format!("{} is not a function", this.display())); + return context + .throw_type_error(format!("{} is not a function", this.display(context))); } let this_arg = args.get(0).cloned().unwrap_or_default(); let arg_array = args.get(1).cloned().unwrap_or_default(); @@ -339,7 +344,7 @@ impl BuiltIn for BuiltInFunctionObject { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event("function", "init"); let function_prototype = context.standard_objects().function_object().prototype(); diff --git a/boa/src/builtins/global_this/mod.rs b/boa/src/builtins/global_this/mod.rs index 42822e40e95..8c3acc74b2a 100644 --- a/boa/src/builtins/global_this/mod.rs +++ b/boa/src/builtins/global_this/mod.rs @@ -25,7 +25,7 @@ impl BuiltIn for GlobalThis { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); ( diff --git a/boa/src/builtins/infinity/mod.rs b/boa/src/builtins/infinity/mod.rs index c04b93afeea..1c0b060d72e 100644 --- a/boa/src/builtins/infinity/mod.rs +++ b/boa/src/builtins/infinity/mod.rs @@ -25,7 +25,7 @@ impl BuiltIn for Infinity { Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT } - fn init(_: &mut Context) -> (&'static str, Value, Attribute) { + fn init(_: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); (Self::NAME, f64::INFINITY.into(), Self::attribute()) diff --git a/boa/src/builtins/iterable/mod.rs b/boa/src/builtins/iterable/mod.rs index 908cbf6b91e..11d0a8e7824 100644 --- a/boa/src/builtins/iterable/mod.rs +++ b/boa/src/builtins/iterable/mod.rs @@ -18,7 +18,7 @@ pub struct IteratorPrototypes { } impl IteratorPrototypes { - pub(crate) fn init(context: &mut Context) -> Self { + pub(crate) fn init(context: &Context) -> Self { let iterator_prototype = create_iterator_prototype(context); Self { iterator_prototype: iterator_prototype @@ -68,7 +68,7 @@ impl IteratorPrototypes { /// CreateIterResultObject( value, done ) /// /// Generates an object supporting the IteratorResult interface. -pub fn create_iter_result_object(context: &mut Context, value: Value, done: bool) -> Value { +pub fn create_iter_result_object(context: &Context, value: Value, done: bool) -> Value { let object = Value::new_object(context); // TODO: Fix attributes of value and done let value_property = DataDescriptor::new(value, Attribute::all()); @@ -79,7 +79,7 @@ pub fn create_iter_result_object(context: &mut Context, value: Value, done: bool } /// Get an iterator record -pub fn get_iterator(context: &mut Context, iterable: Value) -> Result { +pub fn get_iterator(context: &Context, iterable: Value) -> Result { let iterator_function = iterable.get_field(context.well_known_symbols().iterator_symbol(), context)?; if iterator_function.is_null_or_undefined() { @@ -99,7 +99,7 @@ pub fn get_iterator(context: &mut Context, iterable: Value) -> Result Value { +fn create_iterator_prototype(context: &Context) -> Value { let _timer = BoaProfiler::global().start_event("Iterator Prototype", "init"); let symbol_iterator = context.well_known_symbols().iterator_symbol(); @@ -134,7 +134,7 @@ impl IteratorRecord { /// - [ECMA reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-iteratornext - pub(crate) fn next(&self, context: &mut Context) -> Result { + pub(crate) fn next(&self, context: &Context) -> Result { let next = context.call(&self.next_function, &self.iterator_object, &[])?; let done = next.get_field("done", context)?.to_boolean(); diff --git a/boa/src/builtins/json/mod.rs b/boa/src/builtins/json/mod.rs index 3c2313a40d0..90872e3646e 100644 --- a/boa/src/builtins/json/mod.rs +++ b/boa/src/builtins/json/mod.rs @@ -38,7 +38,7 @@ impl BuiltIn for Json { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let json_object = ObjectInitializer::new(context) @@ -63,7 +63,7 @@ impl Json { /// /// [spec]: https://tc39.es/ecma262/#sec-json.parse /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse - pub(crate) fn parse(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn parse(_: &Value, args: &[Value], context: &Context) -> Result { let arg = args .get(0) .cloned() @@ -94,7 +94,7 @@ impl Json { /// [polyfill]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse fn walk( reviver: &Value, - context: &mut Context, + context: &Context, holder: &mut Value, key: &PropertyKey, ) -> Result { @@ -135,7 +135,7 @@ impl Json { /// /// [spec]: https://tc39.es/ecma262/#sec-json.stringify /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify - pub(crate) fn stringify(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn stringify(_: &Value, args: &[Value], context: &Context) -> Result { let object = match args.get(0) { Some(obj) if obj.is_symbol() || obj.is_function() || obj.is_undefined() => { return Ok(Value::undefined()) @@ -223,7 +223,8 @@ impl Json { } else { Some( replacer - .get_property(key) + .get_property(key, context) + .unwrap() .as_ref() .and_then(|p| p.as_data_descriptor()) .map(|d| d.value()) diff --git a/boa/src/builtins/map/map_iterator.rs b/boa/src/builtins/map/map_iterator.rs index a02456d34d7..d5c8aca0292 100644 --- a/boa/src/builtins/map/map_iterator.rs +++ b/boa/src/builtins/map/map_iterator.rs @@ -67,7 +67,7 @@ impl MapIterator { /// - [ECMA reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-%mapiteratorprototype%.next - pub(crate) fn next(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn next(this: &Value, _: &[Value], context: &Context) -> Result { if let Value::Object(ref object) = this { let mut object = object.borrow_mut(); if let Some(map_iterator) = object.as_map_iterator_mut() { @@ -138,7 +138,7 @@ impl MapIterator { /// - [ECMA reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-%mapiteratorprototype%-object - pub(crate) fn create_prototype(context: &mut Context, iterator_prototype: Value) -> Value { + pub(crate) fn create_prototype(context: &Context, iterator_prototype: Value) -> Value { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); // Create prototype diff --git a/boa/src/builtins/map/mod.rs b/boa/src/builtins/map/mod.rs index 7a48f493682..cd8ba4239fe 100644 --- a/boa/src/builtins/map/mod.rs +++ b/boa/src/builtins/map/mod.rs @@ -25,7 +25,7 @@ impl BuiltIn for Map { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let iterator_symbol = context.well_known_symbols().iterator_symbol(); @@ -72,7 +72,7 @@ impl Map { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { if new_target.is_undefined() { return context.throw_type_error("Map requires new"); @@ -153,7 +153,7 @@ impl Map { /// /// [spec]: https://www.ecma-international.org/ecma-262/11.0/index.html#sec-map.prototype.entries /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries - pub(crate) fn entries(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn entries(this: &Value, _: &[Value], context: &Context) -> Result { MapIterator::create_map_iterator(context, this.clone(), MapIterationKind::KeyAndValue) } @@ -167,7 +167,7 @@ impl Map { /// /// [spec]: https://tc39.es/ecma262/#sec-map.prototype.keys /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys - pub(crate) fn keys(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn keys(this: &Value, _: &[Value], context: &Context) -> Result { MapIterator::create_map_iterator(context, this.clone(), MapIterationKind::Key) } @@ -191,7 +191,7 @@ impl Map { /// /// [spec]: https://tc39.es/ecma262/#sec-map.prototype.set /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set - pub(crate) fn set(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn set(this: &Value, args: &[Value], context: &Context) -> Result { let (key, value) = match args.len() { 0 => (Value::Undefined, Value::Undefined), 1 => (args[0].clone(), Value::Undefined), @@ -223,7 +223,7 @@ impl Map { /// /// [spec]: https://tc39.es/ecma262/#sec-map.prototype.delete /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete - pub(crate) fn delete(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn delete(this: &Value, args: &[Value], context: &Context) -> Result { let undefined = Value::Undefined; let key = match args.len() { 0 => &undefined, @@ -254,7 +254,7 @@ impl Map { /// /// [spec]: https://tc39.es/ecma262/#sec-map.prototype.get /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get - pub(crate) fn get(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn get(this: &Value, args: &[Value], context: &Context) -> Result { let undefined = Value::Undefined; let key = match args.len() { 0 => &undefined, @@ -285,7 +285,7 @@ impl Map { /// /// [spec]: https://tc39.es/ecma262/#sec-map.prototype.clear /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear - pub(crate) fn clear(this: &Value, _: &[Value], _: &mut Context) -> Result { + pub(crate) fn clear(this: &Value, _: &[Value], _: &Context) -> Result { this.set_data(ObjectData::Map(OrderedMap::new())); Self::set_size(this, 0); @@ -303,7 +303,7 @@ impl Map { /// /// [spec]: https://tc39.es/ecma262/#sec-map.prototype.has /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has - pub(crate) fn has(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn has(this: &Value, args: &[Value], context: &Context) -> Result { let undefined = Value::Undefined; let key = match args.len() { 0 => &undefined, @@ -330,7 +330,7 @@ impl Map { /// /// [spec]: https://tc39.es/ecma262/#sec-map.prototype.foreach /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/forEach - pub(crate) fn for_each(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn for_each(this: &Value, args: &[Value], context: &Context) -> Result { if args.is_empty() { return Err(Value::from("Missing argument for Map.prototype.forEach")); } @@ -362,12 +362,12 @@ impl Map { /// /// [spec]: https://tc39.es/ecma262/#sec-map.prototype.values /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values - pub(crate) fn values(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn values(this: &Value, _: &[Value], context: &Context) -> Result { MapIterator::create_map_iterator(context, this.clone(), MapIterationKind::Value) } /// Helper function to get a key-value pair from an array. - fn get_key_value(value: &Value, context: &mut Context) -> Result> { + fn get_key_value(value: &Value, context: &Context) -> Result> { if let Value::Object(object) = value { if object.is_array() { let (key, value) = diff --git a/boa/src/builtins/math/mod.rs b/boa/src/builtins/math/mod.rs index ed177fef3a6..e3504e38a52 100644 --- a/boa/src/builtins/math/mod.rs +++ b/boa/src/builtins/math/mod.rs @@ -31,7 +31,7 @@ impl BuiltIn for Math { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; @@ -94,7 +94,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.abs /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/abs - pub(crate) fn abs(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn abs(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -111,7 +111,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.acos /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acos - pub(crate) fn acos(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn acos(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -128,7 +128,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.acosh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acosh - pub(crate) fn acosh(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn acosh(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -145,7 +145,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.asin /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asin - pub(crate) fn asin(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn asin(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -162,7 +162,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.asinh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asinh - pub(crate) fn asinh(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn asinh(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -179,7 +179,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.atan /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan - pub(crate) fn atan(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn atan(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -196,7 +196,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.atanh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atanh - pub(crate) fn atanh(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn atanh(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -213,7 +213,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.atan2 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan2 - pub(crate) fn atan2(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn atan2(_: &Value, args: &[Value], context: &Context) -> Result { Ok(match ( args.get(0).map(|x| x.to_number(context)).transpose()?, args.get(1).map(|x| x.to_number(context)).transpose()?, @@ -232,7 +232,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.cbrt /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cbrt - pub(crate) fn cbrt(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn cbrt(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -249,7 +249,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.ceil /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil - pub(crate) fn ceil(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn ceil(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -266,7 +266,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.clz32 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 - pub(crate) fn clz32(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn clz32(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_u32(context)) @@ -284,7 +284,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.cos /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cos - pub(crate) fn cos(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn cos(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -301,7 +301,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.cosh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cosh - pub(crate) fn cosh(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn cosh(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -318,7 +318,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.exp /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/exp - pub(crate) fn exp(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn exp(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -337,7 +337,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.expm1 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1 - pub(crate) fn expm1(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn expm1(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -354,7 +354,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.floor /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor - pub(crate) fn floor(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn floor(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -371,7 +371,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.fround /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround - pub(crate) fn fround(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn fround(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -388,7 +388,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.hypot /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot - pub(crate) fn hypot(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn hypot(_: &Value, args: &[Value], context: &Context) -> Result { let mut result = 0f64; for arg in args { let x = arg.to_number(context)?; @@ -405,7 +405,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.imul /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul - pub(crate) fn imul(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn imul(_: &Value, args: &[Value], context: &Context) -> Result { Ok(match ( args.get(0).map(|x| x.to_u32(context)).transpose()?, args.get(1).map(|x| x.to_u32(context)).transpose()?, @@ -424,7 +424,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.log /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log - pub(crate) fn log(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn log(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -441,7 +441,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.log1p /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log1p - pub(crate) fn log1p(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn log1p(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -458,7 +458,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.log10 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log10 - pub(crate) fn log10(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn log10(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -475,7 +475,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.log2 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2 - pub(crate) fn log2(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn log2(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -492,7 +492,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.max /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max - pub(crate) fn max(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn max(_: &Value, args: &[Value], context: &Context) -> Result { let mut max = f64::NEG_INFINITY; for arg in args { let num = arg.to_number(context)?; @@ -509,7 +509,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.min /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min - pub(crate) fn min(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn min(_: &Value, args: &[Value], context: &Context) -> Result { let mut min = f64::INFINITY; for arg in args { let num = arg.to_number(context)?; @@ -526,7 +526,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.pow /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow - pub(crate) fn pow(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn pow(_: &Value, args: &[Value], context: &Context) -> Result { Ok(match ( args.get(0).map(|x| x.to_number(context)).transpose()?, args.get(1).map(|x| x.to_number(context)).transpose()?, @@ -545,7 +545,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.random /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random - pub(crate) fn random(_: &Value, _: &[Value], _: &mut Context) -> Result { + pub(crate) fn random(_: &Value, _: &[Value], _: &Context) -> Result { Ok(rand::random::().into()) } @@ -557,7 +557,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.round /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round - pub(crate) fn round(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn round(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -574,7 +574,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.sign /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign - pub(crate) fn sign(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn sign(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -600,7 +600,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.sin /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sin - pub(crate) fn sin(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn sin(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -617,7 +617,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.sinh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sinh - pub(crate) fn sinh(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn sinh(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -634,7 +634,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.sqrt /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt - pub(crate) fn sqrt(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn sqrt(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -651,7 +651,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.tan /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tan - pub(crate) fn tan(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn tan(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -668,7 +668,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.tanh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tanh - pub(crate) fn tanh(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn tanh(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) @@ -685,7 +685,7 @@ impl Math { /// /// [spec]: https://tc39.es/ecma262/#sec-math.trunc /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc - pub(crate) fn trunc(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn trunc(_: &Value, args: &[Value], context: &Context) -> Result { Ok(args .get(0) .map(|x| x.to_number(context)) diff --git a/boa/src/builtins/mod.rs b/boa/src/builtins/mod.rs index 79d19fc87b3..a71f02ee687 100644 --- a/boa/src/builtins/mod.rs +++ b/boa/src/builtins/mod.rs @@ -54,12 +54,12 @@ pub(crate) trait BuiltIn { const NAME: &'static str; fn attribute() -> Attribute; - fn init(context: &mut Context) -> (&'static str, Value, Attribute); + fn init(context: &Context) -> (&'static str, Value, Attribute); } /// Initializes builtin objects and functions #[inline] -pub fn init(context: &mut Context) { +pub fn init(context: &Context) { let globals = [ // Global properties. Undefined::init, diff --git a/boa/src/builtins/nan/mod.rs b/boa/src/builtins/nan/mod.rs index b374c37e385..851e8a0903f 100644 --- a/boa/src/builtins/nan/mod.rs +++ b/boa/src/builtins/nan/mod.rs @@ -26,7 +26,7 @@ impl BuiltIn for NaN { Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT } - fn init(_: &mut Context) -> (&'static str, Value, Attribute) { + fn init(_: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); (Self::NAME, f64::NAN.into(), Self::attribute()) diff --git a/boa/src/builtins/number/mod.rs b/boa/src/builtins/number/mod.rs index 3bae384c67e..013a876683d 100644 --- a/boa/src/builtins/number/mod.rs +++ b/boa/src/builtins/number/mod.rs @@ -49,7 +49,7 @@ impl BuiltIn for Number { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; @@ -156,7 +156,7 @@ impl Number { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let data = match args.get(0) { Some(ref value) => value.to_numeric_number(context)?, @@ -192,7 +192,7 @@ impl Number { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-thisnumbervalue - fn this_number_value(value: &Value, context: &mut Context) -> Result { + fn this_number_value(value: &Value, context: &Context) -> Result { match *value { Value::Integer(integer) => return Ok(f64::from(integer)), Value::Rational(rational) => return Ok(rational), @@ -227,11 +227,7 @@ impl Number { /// [spec]: https://tc39.es/ecma262/#sec-number.prototype.toexponential /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toExponential #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_exponential( - this: &Value, - _: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn to_exponential(this: &Value, _: &[Value], context: &Context) -> Result { let this_num = Self::this_number_value(this, context)?; let this_str_num = Self::num_to_exponential(this_num); Ok(Value::from(this_str_num)) @@ -248,7 +244,7 @@ impl Number { /// [spec]: https://tc39.es/ecma262/#sec-number.prototype.tofixed /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_fixed(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_fixed(this: &Value, args: &[Value], context: &Context) -> Result { let this_num = Self::this_number_value(this, context)?; let precision = match args.get(0) { Some(n) => match n.to_integer(context)? as i32 { @@ -275,11 +271,7 @@ impl Number { /// [spec]: https://tc39.es/ecma262/#sec-number.prototype.tolocalestring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_locale_string( - this: &Value, - _: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn to_locale_string(this: &Value, _: &[Value], context: &Context) -> Result { let this_num = Self::this_number_value(this, context)?; let this_str_num = format!("{}", this_num); Ok(Value::from(this_str_num)) @@ -353,11 +345,7 @@ impl Number { /// [spec]: https://tc39.es/ecma262/#sec-number.prototype.toprecision /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_precision( - this: &Value, - args: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn to_precision(this: &Value, args: &[Value], context: &Context) -> Result { let precision_var = args.get(0).cloned().unwrap_or_default(); // 1 & 6 @@ -594,7 +582,7 @@ impl Number { /// [spec]: https://tc39.es/ecma262/#sec-number.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_string(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_string(this: &Value, args: &[Value], context: &Context) -> Result { // 1. Let x be ? thisNumberValue(this value). let x = Self::this_number_value(this, context)?; @@ -649,7 +637,7 @@ impl Number { /// /// [spec]: https://tc39.es/ecma262/#sec-number.prototype.valueof /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/valueOf - pub(crate) fn value_of(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn value_of(this: &Value, _: &[Value], context: &Context) -> Result { Ok(Value::from(Self::this_number_value(this, context)?)) } @@ -667,7 +655,7 @@ impl Number { /// /// [spec]: https://tc39.es/ecma262/#sec-parseint-string-radix /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt - pub(crate) fn parse_int(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn parse_int(_: &Value, args: &[Value], context: &Context) -> Result { if let (Some(val), radix) = (args.get(0), args.get(1)) { // 1. Let inputString be ? ToString(string). let input_string = val.to_string(context)?; @@ -789,7 +777,7 @@ impl Number { /// /// [spec]: https://tc39.es/ecma262/#sec-parsefloat-string /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat - pub(crate) fn parse_float(_: &Value, args: &[Value], _ctx: &mut Context) -> Result { + pub(crate) fn parse_float(_: &Value, args: &[Value], _ctx: &Context) -> Result { if let Some(val) = args.get(0) { match val { Value::String(s) => { @@ -831,11 +819,7 @@ impl Number { /// /// [spec]: https://tc39.es/ecma262/#sec-isfinite-number /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite - pub(crate) fn global_is_finite( - _: &Value, - args: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn global_is_finite(_: &Value, args: &[Value], context: &Context) -> Result { if let Some(value) = args.get(0) { let number = value.to_number(context)?; Ok(number.is_finite().into()) @@ -858,7 +842,7 @@ impl Number { /// /// [spec]: https://tc39.es/ecma262/#sec-isnan-number /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN - pub(crate) fn global_is_nan(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn global_is_nan(_: &Value, args: &[Value], context: &Context) -> Result { if let Some(value) = args.get(0) { let number = value.to_number(context)?; Ok(number.is_nan().into()) @@ -881,7 +865,7 @@ impl Number { /// /// [spec]: https://tc39.es/ecma262/#sec-number.isfinite /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite - pub(crate) fn number_is_finite(_: &Value, args: &[Value], _ctx: &mut Context) -> Result { + pub(crate) fn number_is_finite(_: &Value, args: &[Value], _ctx: &Context) -> Result { Ok(Value::from(if let Some(val) = args.get(0) { match val { Value::Integer(_) => true, @@ -903,11 +887,7 @@ impl Number { /// /// [spec]: https://tc39.es/ecma262/#sec-number.isinteger /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger - pub(crate) fn number_is_integer( - _: &Value, - args: &[Value], - _ctx: &mut Context, - ) -> Result { + pub(crate) fn number_is_integer(_: &Value, args: &[Value], _ctx: &Context) -> Result { Ok(args.get(0).map_or(false, Self::is_integer).into()) } @@ -925,7 +905,7 @@ impl Number { /// /// [spec]: https://tc39.es/ecma262/#sec-isnan-number /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN - pub(crate) fn number_is_nan(_: &Value, args: &[Value], _ctx: &mut Context) -> Result { + pub(crate) fn number_is_nan(_: &Value, args: &[Value], _ctx: &Context) -> Result { Ok(Value::from(if let Some(val) = args.get(0) { match val { Value::Integer(_) => false, @@ -951,7 +931,7 @@ impl Number { /// /// [spec]: https://tc39.es/ecma262/#sec-isnan-number /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN - pub(crate) fn is_safe_integer(_: &Value, args: &[Value], _ctx: &mut Context) -> Result { + pub(crate) fn is_safe_integer(_: &Value, args: &[Value], _ctx: &Context) -> Result { Ok(Value::from(match args.get(0) { Some(Value::Integer(_)) => true, Some(Value::Rational(number)) if Self::is_float_integer(*number) => { diff --git a/boa/src/builtins/object/for_in_iterator.rs b/boa/src/builtins/object/for_in_iterator.rs index d5ea5ee61ef..e460da488c4 100644 --- a/boa/src/builtins/object/for_in_iterator.rs +++ b/boa/src/builtins/object/for_in_iterator.rs @@ -63,14 +63,14 @@ impl ForInIterator { /// - [ECMA reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-%foriniteratorprototype%.next - pub(crate) fn next(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn next(this: &Value, _: &[Value], context: &Context) -> Result { if let Value::Object(ref o) = this { let mut for_in_iterator = o.borrow_mut(); if let Some(iterator) = for_in_iterator.as_for_in_iterator_mut() { let mut object = iterator.object.to_object(context)?; loop { if !iterator.object_was_visited { - let keys = object.own_property_keys(); + let keys = object.own_property_keys(context)?; for k in keys { match k { PropertyKey::String(ref k) => { @@ -87,7 +87,7 @@ impl ForInIterator { while let Some(r) = iterator.remaining_keys.pop_front() { if !iterator.visited_keys.contains(&r) { if let Some(desc) = - object.get_own_property(&PropertyKey::from(r.clone())) + object.get_own_property(&PropertyKey::from(r.clone()), context)? { iterator.visited_keys.insert(r.clone()); if desc.enumerable() { @@ -125,7 +125,7 @@ impl ForInIterator { /// - [ECMA reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-%foriniteratorprototype%-object - pub(crate) fn create_prototype(context: &mut Context, iterator_prototype: Value) -> Value { + pub(crate) fn create_prototype(context: &Context, iterator_prototype: Value) -> Value { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); // Create prototype diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index fd6f4239141..0a0ef7c588a 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -40,7 +40,7 @@ impl BuiltIn for Object { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let object = ConstructorBuilder::with_standard_object( @@ -80,7 +80,7 @@ impl BuiltIn for Object { impl Object { const LENGTH: usize = 1; - fn constructor(new_target: &Value, args: &[Value], context: &mut Context) -> Result { + fn constructor(new_target: &Value, args: &[Value], context: &Context) -> Result { if !new_target.is_undefined() { let prototype = new_target .as_object() @@ -117,7 +117,7 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#sec-object.create /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create - pub fn create(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub fn create(_: &Value, args: &[Value], context: &Context) -> Result { let prototype = args.get(0).cloned().unwrap_or_else(Value::undefined); let properties = args.get(1).cloned().unwrap_or_else(Value::undefined); @@ -129,7 +129,7 @@ impl Object { _ => { return context.throw_type_error(format!( "Object prototype may only be an Object or null: {}", - prototype.display() + prototype.display(context) )) } }; @@ -154,7 +154,7 @@ impl Object { pub fn get_own_property_descriptor( _: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let object = args .get(0) @@ -163,7 +163,7 @@ impl Object { if let Some(key) = args.get(1) { let key = key.to_property_key(context)?; - if let Some(desc) = object.get_own_property(&key) { + if let Some(desc) = object.get_own_property(&key, context)? { return Ok(Self::from_property_descriptor(desc, context)?); } } @@ -184,7 +184,7 @@ impl Object { pub fn get_own_property_descriptors( _: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let object = args .get(0) @@ -195,7 +195,7 @@ impl Object { for key in object.borrow().keys() { let descriptor = { let desc = object - .get_own_property(&key) + .get_own_property(&key, context)? .expect("Expected property to be on object."); Self::from_property_descriptor(desc, context)? }; @@ -216,7 +216,7 @@ impl Object { /// [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-frompropertydescriptor - fn from_property_descriptor(desc: PropertyDescriptor, context: &mut Context) -> Result { + fn from_property_descriptor(desc: PropertyDescriptor, context: &Context) -> Result { let mut descriptor = ObjectInitializer::new(context); if let PropertyDescriptor::Data(data_desc) = &desc { @@ -255,7 +255,7 @@ impl Object { } /// Uses the SameValue algorithm to check equality of objects - pub fn is(_: &Value, args: &[Value], _: &mut Context) -> Result { + pub fn is(_: &Value, args: &[Value], _: &Context) -> Result { let x = args.get(0).cloned().unwrap_or_else(Value::undefined); let y = args.get(1).cloned().unwrap_or_else(Value::undefined); @@ -263,7 +263,7 @@ impl Object { } /// Get the `prototype` of an object. - pub fn get_prototype_of(_: &Value, args: &[Value], ctx: &mut Context) -> Result { + pub fn get_prototype_of(_: &Value, args: &[Value], ctx: &Context) -> Result { if args.is_empty() { return ctx.throw_type_error( "Object.getPrototypeOf: At least 1 argument required, but only 0 passed", @@ -282,7 +282,7 @@ impl Object { /// [More information][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-object.setprototypeof - pub fn set_prototype_of(_: &Value, args: &[Value], ctx: &mut Context) -> Result { + pub fn set_prototype_of(_: &Value, args: &[Value], ctx: &Context) -> Result { if args.len() < 2 { return ctx.throw_type_error(format!( "Object.setPrototypeOf: At least 2 arguments required, but only {} passed", @@ -316,7 +316,7 @@ impl Object { let status = obj .as_object() .expect("obj was not an object") - .set_prototype_of(proto); + .set_prototype_of(proto, ctx)?; // 5. If status is false, throw a TypeError exception. if !status { @@ -337,7 +337,7 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#sec-object.prototype.isprototypeof /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf - pub fn is_prototype_of(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub fn is_prototype_of(this: &Value, args: &[Value], context: &Context) -> Result { let undefined = Value::undefined(); let mut v = args.get(0).unwrap_or(&undefined).clone(); if !v.is_object() { @@ -356,7 +356,7 @@ impl Object { } /// Define a property in an object - pub fn define_property(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub fn define_property(_: &Value, args: &[Value], context: &Context) -> Result { let object = args.get(0).cloned().unwrap_or_else(Value::undefined); if let Some(mut object) = object.as_object() { let key = args @@ -386,7 +386,7 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#sec-object.defineproperties /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties - pub fn define_properties(_: &Value, args: &[Value], context: &mut Context) -> Result { + pub fn define_properties(_: &Value, args: &[Value], context: &Context) -> Result { let arg = args.get(0).cloned().unwrap_or_default(); let arg_obj = arg.as_object(); if let Some(mut obj) = arg_obj { @@ -408,7 +408,7 @@ impl Object { /// [spec]: https://tc39.es/ecma262/#sec-object.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString #[allow(clippy::wrong_self_convention)] - pub fn to_string(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub fn to_string(this: &Value, _: &[Value], context: &Context) -> Result { if this.is_undefined() { Ok("[object Undefined]".into()) } else if this.is_null() { @@ -454,7 +454,7 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#sec-object.prototype.hasownproperty /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty - pub fn has_own_property(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub fn has_own_property(this: &Value, args: &[Value], context: &Context) -> Result { let key = args .get(0) .unwrap_or(&Value::undefined()) @@ -467,7 +467,7 @@ impl Object { pub fn property_is_enumerable( this: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { let key = match args.get(0) { None => return Ok(Value::from(false)), @@ -475,7 +475,7 @@ impl Object { }; let key = key.to_property_key(context)?; - let own_property = this.to_object(context)?.get_own_property(&key); + let own_property = this.to_object(context)?.get_own_property(&key, context)?; Ok(own_property.map_or(Value::from(false), |own_prop| { Value::from(own_prop.enumerable()) diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index 0b40e238e26..e1c5800f5c0 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -68,7 +68,7 @@ impl BuiltIn for RegExp { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let regexp_object = ConstructorBuilder::with_standard_object( @@ -98,11 +98,7 @@ impl RegExp { pub(crate) const LENGTH: usize = 2; /// Create a new `RegExp` - pub(crate) fn constructor( - new_target: &Value, - args: &[Value], - ctx: &mut Context, - ) -> Result { + pub(crate) fn constructor(new_target: &Value, args: &[Value], ctx: &Context) -> Result { let prototype = new_target .as_object() .and_then(|obj| { @@ -217,7 +213,7 @@ impl RegExp { // /// // /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.dotAll // /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/dotAll - // fn get_dot_all(this: &Value, _: &[Value], _: &mut Context) -> Result { + // fn get_dot_all(this: &Value, _: &[Value], _: &Context) -> Result { // this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.dot_all))) // } @@ -232,7 +228,7 @@ impl RegExp { // /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.flags // /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags // /// [flags]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2 - // fn get_flags(this: &Value, _: &[Value], _: &mut Context) -> Result { + // fn get_flags(this: &Value, _: &[Value], _: &Context) -> Result { // this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.flags.clone()))) // } @@ -246,7 +242,7 @@ impl RegExp { // /// // /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.global // /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/global - // fn get_global(this: &Value, _: &[Value], _: &mut Context) -> Result { + // fn get_global(this: &Value, _: &[Value], _: &Context) -> Result { // this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.global))) // } @@ -260,7 +256,7 @@ impl RegExp { // /// // /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.ignorecase // /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/ignoreCase - // fn get_ignore_case(this: &Value, _: &[Value], _: &mut Context) -> Result { + // fn get_ignore_case(this: &Value, _: &[Value], _: &Context) -> Result { // this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.ignore_case))) // } @@ -274,7 +270,7 @@ impl RegExp { // /// // /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.multiline // /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/multiline - // fn get_multiline(this: &Value, _: &[Value], _: &mut Context) -> Result { + // fn get_multiline(this: &Value, _: &[Value], _: &Context) -> Result { // this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.multiline))) // } @@ -289,7 +285,7 @@ impl RegExp { // /// // /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.source // /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/source - // fn get_source(this: &Value, _: &[Value], _: &mut Context) -> Result { + // fn get_source(this: &Value, _: &[Value], _: &Context) -> Result { // Ok(this.get_internal_slot("OriginalSource")) // } @@ -303,7 +299,7 @@ impl RegExp { // /// // /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.sticky // /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky - // fn get_sticky(this: &Value, _: &[Value], _: &mut Context) -> Result { + // fn get_sticky(this: &Value, _: &[Value], _: &Context) -> Result { // this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.sticky))) // } @@ -318,7 +314,7 @@ impl RegExp { // /// // /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.unicode // /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode - // fn get_unicode(this: &Value, _: &[Value], _: &mut Context) -> Result { + // fn get_unicode(this: &Value, _: &[Value], _: &Context) -> Result { // this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.unicode))) // } @@ -334,7 +330,7 @@ impl RegExp { /// /// [spec]: https://tc39.es/ecma262/#sec-regexp.prototype.test /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test - pub(crate) fn test(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn test(this: &Value, args: &[Value], context: &Context) -> Result { let mut last_index = this.get_field("lastIndex", context)?.to_index(context)?; let result = if let Some(object) = this.as_object() { // 3. Let string be ? ToString(S). @@ -387,7 +383,7 @@ impl RegExp { /// /// [spec]: https://tc39.es/ecma262/#sec-regexp.prototype.exec /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec - pub(crate) fn exec(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn exec(this: &Value, args: &[Value], context: &Context) -> Result { // 4. Return ? RegExpBuiltinExec(R, S). let mut last_index = this.get_field("lastIndex", context)?.to_index(context)?; let result = if let Some(object) = this.as_object() { @@ -457,7 +453,7 @@ impl RegExp { /// /// [spec]: https://tc39.es/ecma262/#sec-regexp.prototype-@@match /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@match - pub(crate) fn r#match(this: &Value, arg: RcString, context: &mut Context) -> Result { + pub(crate) fn r#match(this: &Value, arg: RcString, context: &Context) -> Result { let (matcher, flags) = if let Some(object) = this.as_object() { let object = object.borrow(); if let Some(regex) = object.as_regexp() { @@ -495,20 +491,20 @@ impl RegExp { /// [spec]: https://tc39.es/ecma262/#sec-regexp.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/toString #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_string(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_string(this: &Value, _: &[Value], context: &Context) -> Result { let (body, flags) = if let Some(object) = this.as_object() { let object = object.borrow(); let regex = object.as_regexp().ok_or_else(|| { context.construct_type_error(format!( "Method RegExp.prototype.toString called on incompatible receiver {}", - this.display() + this.display(context) )) })?; (regex.original_source.clone(), regex.flags.clone()) } else { return context.throw_type_error(format!( "Method RegExp.prototype.toString called on incompatible receiver {}", - this.display() + this.display(context) )); }; Ok(Value::from(format!("/{}/{}", body, flags))) @@ -525,7 +521,7 @@ impl RegExp { /// [spec]: https://tc39.es/ecma262/#sec-regexp-prototype-matchall /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@matchAll // TODO: it's returning an array, it should return an iterator - pub(crate) fn match_all(this: &Value, arg_str: String, context: &mut Context) -> Result { + pub(crate) fn match_all(this: &Value, arg_str: String, context: &Context) -> Result { let matches = if let Some(object) = this.as_object() { let object = object.borrow(); if let Some(regex) = object.as_regexp() { diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index 9749b9516eb..c84cd71d6dc 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -71,7 +71,7 @@ impl BuiltIn for String { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let symbol_iterator = context.well_known_symbols().iterator_symbol(); @@ -135,7 +135,7 @@ impl String { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { // This value is used by console.log and other routines to match Object type // to its Javascript Identifier (global constructor method name) @@ -179,7 +179,7 @@ impl String { Ok(this) } - fn this_string_value(this: &Value, context: &mut Context) -> Result { + fn this_string_value(this: &Value, context: &Context) -> Result { match this { Value::String(ref string) => return Ok(string.clone()), Value::Object(ref object) => { @@ -197,7 +197,7 @@ impl String { /// Get the string value to a primitive string #[allow(clippy::wrong_self_convention)] #[inline] - pub(crate) fn to_string(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_string(this: &Value, _: &[Value], context: &Context) -> Result { // Get String from String Object and send it back as a new value Ok(Value::from(Self::this_string_value(this, context)?)) } @@ -218,7 +218,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.charat /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt - pub(crate) fn char_at(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn char_at(this: &Value, args: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; @@ -258,11 +258,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.codepointat /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt - pub(crate) fn code_point_at( - this: &Value, - args: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn code_point_at(this: &Value, args: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; @@ -298,11 +294,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.charcodeat /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt - pub(crate) fn char_code_at( - this: &Value, - args: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn char_code_at(this: &Value, args: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; @@ -341,7 +333,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.concat /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/concat - pub(crate) fn concat(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn concat(this: &Value, args: &[Value], context: &Context) -> Result { let object = this.require_object_coercible(context)?; let mut string = object.to_string(context)?.to_string(); @@ -363,7 +355,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.repeat /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat - pub(crate) fn repeat(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn repeat(this: &Value, args: &[Value], context: &Context) -> Result { let object = this.require_object_coercible(context)?; let string = object.to_string(context)?; @@ -397,7 +389,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.slice /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice - pub(crate) fn slice(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn slice(this: &Value, args: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; @@ -448,11 +440,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.startswith /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith - pub(crate) fn starts_with( - this: &Value, - args: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn starts_with(this: &Value, args: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; @@ -501,7 +489,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.endswith /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith - pub(crate) fn ends_with(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn ends_with(this: &Value, args: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; @@ -551,7 +539,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.includes /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes - pub(crate) fn includes(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn includes(this: &Value, args: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; @@ -624,7 +612,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.replace /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace - pub(crate) fn replace(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn replace(this: &Value, args: &[Value], context: &Context) -> Result { // TODO: Support Symbol replacer let primitive_val = this.to_string(context)?; if args.is_empty() { @@ -783,7 +771,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.indexof /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf - pub(crate) fn index_of(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn index_of(this: &Value, args: &[Value], context: &Context) -> Result { let this = this.require_object_coercible(context)?; let string = this.to_string(context)?; @@ -826,11 +814,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.lastindexof /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf - pub(crate) fn last_index_of( - this: &Value, - args: &[Value], - context: &mut Context, - ) -> Result { + pub(crate) fn last_index_of(this: &Value, args: &[Value], context: &Context) -> Result { let this = this.require_object_coercible(context)?; let string = this.to_string(context)?; @@ -871,7 +855,7 @@ impl String { /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.match /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match /// [regex]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions - pub(crate) fn r#match(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn r#match(this: &Value, args: &[Value], context: &Context) -> Result { let re = RegExp::constructor( &Value::from(Object::default()), &[args.get(0).cloned().unwrap_or_default()], @@ -926,7 +910,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.padend /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd - pub(crate) fn pad_end(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn pad_end(this: &Value, args: &[Value], context: &Context) -> Result { let primitive = this.to_string(context)?; if args.is_empty() { return Err(Value::from("padEnd requires maxLength argument")); @@ -953,7 +937,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.padstart /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart - pub(crate) fn pad_start(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn pad_start(this: &Value, args: &[Value], context: &Context) -> Result { let primitive = this.to_string(context)?; if args.is_empty() { return Err(Value::from("padStart requires maxLength argument")); @@ -1001,7 +985,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.trim /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim - pub(crate) fn trim(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn trim(this: &Value, _: &[Value], context: &Context) -> Result { let this = this.require_object_coercible(context)?; let string = this.to_string(context)?; Ok(Value::from( @@ -1021,7 +1005,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.trimstart /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trimStart - pub(crate) fn trim_start(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn trim_start(this: &Value, _: &[Value], context: &Context) -> Result { let string = this.to_string(context)?; Ok(Value::from( string.trim_start_matches(Self::is_trimmable_whitespace), @@ -1040,7 +1024,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.trimend /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trimEnd - pub(crate) fn trim_end(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn trim_end(this: &Value, _: &[Value], context: &Context) -> Result { let this = this.require_object_coercible(context)?; let string = this.to_string(context)?; Ok(Value::from( @@ -1059,7 +1043,7 @@ impl String { /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.tolowercase /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_lowercase(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_lowercase(this: &Value, _: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let this_str = this.to_string(context)?; @@ -1081,7 +1065,7 @@ impl String { /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.toUppercase /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_uppercase(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_uppercase(this: &Value, _: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let this_str = this.to_string(context)?; @@ -1100,7 +1084,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.substring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring - pub(crate) fn substring(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn substring(this: &Value, args: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; @@ -1151,7 +1135,7 @@ impl String { /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.substr /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr /// - pub(crate) fn substr(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn substr(this: &Value, args: &[Value], context: &Context) -> Result { // First we get it the actual string a private field stored on the object only the context has access to. // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; @@ -1209,7 +1193,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.split /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split - pub(crate) fn split(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn split(this: &Value, args: &[Value], context: &Context) -> Result { let this = this.require_object_coercible(context)?; let string = this.to_string(context)?; @@ -1279,7 +1263,7 @@ impl String { /// /// [spec]: https://tc39.es/ecma262/#sec-string.prototype.value_of /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/valueOf - pub(crate) fn value_of(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn value_of(this: &Value, args: &[Value], context: &Context) -> Result { // Use the to_string method because it is specified to do the same thing in this case Self::to_string(this, args, context) } @@ -1297,7 +1281,7 @@ impl String { /// [regex]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions /// [cg]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges // TODO: update this method to return iterator - pub(crate) fn match_all(this: &Value, args: &[Value], context: &mut Context) -> Result { + pub(crate) fn match_all(this: &Value, args: &[Value], context: &Context) -> Result { let re: Value = match args.get(0) { Some(arg) => { if arg.is_null() { @@ -1326,7 +1310,7 @@ impl String { RegExp::match_all(&re, this.to_string(context)?.to_string(), context) } - pub(crate) fn iterator(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn iterator(this: &Value, _: &[Value], context: &Context) -> Result { StringIterator::create_string_iterator(context, this.clone()) } } diff --git a/boa/src/builtins/string/string_iterator.rs b/boa/src/builtins/string/string_iterator.rs index e1a56748015..6229a987784 100644 --- a/boa/src/builtins/string/string_iterator.rs +++ b/boa/src/builtins/string/string_iterator.rs @@ -22,7 +22,7 @@ impl StringIterator { } } - pub fn create_string_iterator(context: &mut Context, string: Value) -> Result { + pub fn create_string_iterator(context: &Context, string: Value) -> Result { let string_iterator = Value::new_object(context); string_iterator.set_data(ObjectData::StringIterator(Self::new(string))); string_iterator @@ -32,7 +32,7 @@ impl StringIterator { Ok(string_iterator) } - pub fn next(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub fn next(this: &Value, _: &[Value], context: &Context) -> Result { if let Value::Object(ref object) = this { let mut object = object.borrow_mut(); if let Some(string_iterator) = object.as_string_iterator_mut() { @@ -69,7 +69,7 @@ impl StringIterator { /// - [ECMA reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-%arrayiteratorprototype%-object - pub(crate) fn create_prototype(context: &mut Context, iterator_prototype: Value) -> Value { + pub(crate) fn create_prototype(context: &Context, iterator_prototype: Value) -> Value { let _timer = BoaProfiler::global().start_event("String Iterator", "init"); // Create prototype diff --git a/boa/src/builtins/symbol/mod.rs b/boa/src/builtins/symbol/mod.rs index 05d1c60be88..faea896868c 100644 --- a/boa/src/builtins/symbol/mod.rs +++ b/boa/src/builtins/symbol/mod.rs @@ -240,7 +240,7 @@ impl BuiltIn for Symbol { Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE } - fn init(context: &mut Context) -> (&'static str, Value, Attribute) { + fn init(context: &Context) -> (&'static str, Value, Attribute) { // https://tc39.es/ecma262/#sec-well-known-symbols let well_known_symbols = context.well_known_symbols(); @@ -318,7 +318,7 @@ impl Symbol { pub(crate) fn constructor( new_target: &Value, args: &[Value], - context: &mut Context, + context: &Context, ) -> Result { if new_target.is_undefined() { return context.throw_type_error("Symbol is not a constructor"); @@ -331,7 +331,7 @@ impl Symbol { Ok(context.construct_symbol(description).into()) } - fn this_symbol_value(value: &Value, context: &mut Context) -> Result { + fn this_symbol_value(value: &Value, context: &Context) -> Result { match value { Value::Symbol(ref symbol) => return Ok(symbol.clone()), Value::Object(ref object) => { @@ -357,7 +357,7 @@ impl Symbol { /// [spec]: https://tc39.es/ecma262/#sec-symbol.prototype.tostring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toString #[allow(clippy::wrong_self_convention)] - pub(crate) fn to_string(this: &Value, _: &[Value], context: &mut Context) -> Result { + pub(crate) fn to_string(this: &Value, _: &[Value], context: &Context) -> Result { let symbol = Self::this_symbol_value(this, context)?; let description = symbol.description().unwrap_or(""); Ok(Value::from(format!("Symbol({})", description))) diff --git a/boa/src/builtins/symbol/tests.rs b/boa/src/builtins/symbol/tests.rs index f311d29c5e7..3b38b44a907 100644 --- a/boa/src/builtins/symbol/tests.rs +++ b/boa/src/builtins/symbol/tests.rs @@ -19,7 +19,7 @@ fn print_symbol_expect_description() { "#; eprintln!("{}", forward(&mut context, init)); let sym = forward_val(&mut context, "sym.toString()").unwrap(); - assert_eq!(sym.display().to_string(), "\"Symbol(Hello)\""); + assert_eq!(sym.display(&context).to_string(), "\"Symbol(Hello)\""); } #[test] diff --git a/boa/src/builtins/undefined/mod.rs b/boa/src/builtins/undefined/mod.rs index 91760b427a4..446dcb6273e 100644 --- a/boa/src/builtins/undefined/mod.rs +++ b/boa/src/builtins/undefined/mod.rs @@ -25,7 +25,7 @@ impl BuiltIn for Undefined { Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT } - fn init(_: &mut Context) -> (&'static str, Value, Attribute) { + fn init(_: &Context) -> (&'static str, Value, Attribute) { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); (Self::NAME, Value::undefined(), Self::attribute()) diff --git a/boa/src/class.rs b/boa/src/class.rs index 6f33c154f38..ae11f053007 100644 --- a/boa/src/class.rs +++ b/boa/src/class.rs @@ -25,7 +25,7 @@ //! const LENGTH: usize = 1; //! //! // This is what is called when we do `new Animal()` -//! fn constructor(_this: &Value, args: &[Value], context: &mut Context) -> Result { +//! fn constructor(_this: &Value, args: &[Value], context: &Context) -> Result { //! // This is equivalent to `String(arg)`. //! let kind = args.get(0).cloned().unwrap_or_default().to_string(context)?; //! @@ -77,7 +77,7 @@ pub trait Class: NativeObject + Sized { const ATTRIBUTE: Attribute = Attribute::all(); /// The constructor of the class. - fn constructor(this: &Value, args: &[Value], context: &mut Context) -> Result; + fn constructor(this: &Value, args: &[Value], context: &Context) -> Result; /// Initializes the internals and the methods of the class. fn init(class: &mut ClassBuilder<'_>) -> Result<()>; @@ -88,13 +88,13 @@ pub trait Class: NativeObject + Sized { /// This is automatically implemented, when a type implements `Class`. pub trait ClassConstructor: Class { /// The raw constructor that mathces the `NativeFunction` signature. - fn raw_constructor(this: &Value, args: &[Value], context: &mut Context) -> Result + fn raw_constructor(this: &Value, args: &[Value], context: &Context) -> Result where Self: Sized; } impl ClassConstructor for T { - fn raw_constructor(this: &Value, args: &[Value], context: &mut Context) -> Result + fn raw_constructor(this: &Value, args: &[Value], context: &Context) -> Result where Self: Sized, { @@ -112,7 +112,7 @@ pub struct ClassBuilder<'context> { impl<'context> ClassBuilder<'context> { #[inline] - pub(crate) fn new(context: &'context mut Context) -> Self + pub(crate) fn new(context: &'context Context) -> Self where T: ClassConstructor, { @@ -184,7 +184,7 @@ impl<'context> ClassBuilder<'context> { /// Return the current context. #[inline] - pub fn context(&mut self) -> &'_ mut Context { + pub fn context(&mut self) -> &'_ Context { self.builder.context() } } diff --git a/boa/src/context.rs b/boa/src/context.rs index 3bf38c6cc4e..cdb7128f287 100644 --- a/boa/src/context.rs +++ b/boa/src/context.rs @@ -6,6 +6,7 @@ use crate::{ function::{Function, FunctionFlags, NativeFunction}, iterable::IteratorPrototypes, symbol::{Symbol, WellKnownSymbols}, + EvalError, RangeError, ReferenceError, SyntaxError, TypeError, UriError, }, class::{Class, ClassBuilder}, exec::Interpreter, @@ -14,11 +15,8 @@ use crate::{ realm::Realm, syntax::{ ast::{ - node::{ - statement_list::RcStatementList, Call, FormalParameter, Identifier, New, - StatementList, - }, - Const, Node, + node::{statement_list::RcStatementList, FormalParameter, StatementList}, + Node, }, Parser, }, @@ -35,6 +33,7 @@ use crate::vm::{ compilation::{CodeGen, Compiler}, VM, }; +use std::cell::{Cell, RefCell}; /// Store a builtin constructor (such as `Object`) and its corresponding prototype. #[derive(Debug, Clone)] @@ -214,16 +213,16 @@ pub struct Context { realm: Realm, /// The current executor. - executor: Interpreter, + executor: RefCell, /// Symbol hash. /// /// For now this is an incremented u64 number. - symbol_count: u64, + symbol_count: Cell, /// console object state. #[cfg(feature = "console")] - console: Console, + console: RefCell, /// Cached well known symbols well_known_symbols: WellKnownSymbols, @@ -242,10 +241,10 @@ impl Default for Context { let (well_known_symbols, symbol_count) = WellKnownSymbols::new(); let mut context = Self { realm, - executor, - symbol_count, + executor: RefCell::new(executor), + symbol_count: Cell::new(symbol_count), #[cfg(feature = "console")] - console: Console::default(), + console: RefCell::new(Console::default()), well_known_symbols, iterator_prototypes: IteratorPrototypes::default(), standard_objects: Default::default(), @@ -255,7 +254,7 @@ impl Default for Context { // At a later date this can be removed from here and called explicitly, // but for now we almost always want these default builtins context.create_intrinsics(); - context.iterator_prototypes = IteratorPrototypes::init(&mut context); + context.iterator_prototypes = IteratorPrototypes::init(&context); context } } @@ -278,23 +277,16 @@ impl Context { } #[inline] - pub fn executor(&mut self) -> &mut Interpreter { - &mut self.executor + pub fn executor(&self) -> &RefCell { + &self.executor } /// A helper function for getting an immutable reference to the `console` object. #[cfg(feature = "console")] - pub(crate) fn console(&self) -> &Console { + pub(crate) fn console(&self) -> &RefCell { &self.console } - /// A helper function for getting a mutable reference to the `console` object. - #[cfg(feature = "console")] - #[inline] - pub(crate) fn console_mut(&mut self) -> &mut Console { - &mut self.console - } - /// Sets up the default global objects within Global #[inline] fn create_intrinsics(&mut self) { @@ -307,15 +299,15 @@ impl Context { /// /// This currently is an incremented value. #[inline] - fn generate_hash(&mut self) -> u64 { - let hash = self.symbol_count; - self.symbol_count += 1; + fn generate_hash(&self) -> u64 { + let hash = self.symbol_count.get(); + self.symbol_count.replace(hash + 1); hash } /// Construct a new `Symbol` with an optional description. #[inline] - pub fn construct_symbol(&mut self, description: Option) -> RcSymbol { + pub fn construct_symbol(&self, description: Option) -> RcSymbol { RcSymbol::from(Symbol::new(self.generate_hash(), description)) } @@ -328,7 +320,7 @@ impl Context { /// #[inline] - pub(crate) fn call(&mut self, f: &Value, this: &Value, args: &[Value]) -> Result { + pub(crate) fn call(&self, f: &Value, this: &Value, args: &[Value]) -> Result { match *f { Value::Object(ref object) => object.call(this, args, self), _ => self.throw_type_error("not a function"), @@ -343,22 +335,18 @@ impl Context { /// Constructs a `RangeError` with the specified message. #[inline] - pub fn construct_range_error(&mut self, message: M) -> Value + pub fn construct_range_error(&self, message: M) -> Value where M: Into>, { - // Runs a `new RangeError(message)`. - New::from(Call::new( - Identifier::from("RangeError"), - vec![Const::from(message.into()).into()], - )) - .run(self) - .expect("Into used as message") + let message = message.into(); + RangeError::constructor(&Value::undefined(), &[Value::from(message)], self) + .expect("Into used as message") } /// Throws a `RangeError` with the specified message. #[inline] - pub fn throw_range_error(&mut self, message: M) -> Result + pub fn throw_range_error(&self, message: M) -> Result where M: Into>, { @@ -367,22 +355,18 @@ impl Context { /// Constructs a `TypeError` with the specified message. #[inline] - pub fn construct_type_error(&mut self, message: M) -> Value + pub fn construct_type_error(&self, message: M) -> Value where M: Into>, { - // Runs a `new TypeError(message)`. - New::from(Call::new( - Identifier::from("TypeError"), - vec![Const::from(message.into()).into()], - )) - .run(self) - .expect("Into used as message") + let message = message.into(); + TypeError::constructor(&Value::undefined(), &[Value::from(message)], self) + .expect("Into used as message") } /// Throws a `TypeError` with the specified message. #[inline] - pub fn throw_type_error(&mut self, message: M) -> Result + pub fn throw_type_error(&self, message: M) -> Result where M: Into>, { @@ -391,21 +375,18 @@ impl Context { /// Constructs a `ReferenceError` with the specified message. #[inline] - pub fn construct_reference_error(&mut self, message: M) -> Value + pub fn construct_reference_error(&self, message: M) -> Value where M: Into>, { - New::from(Call::new( - Identifier::from("ReferenceError"), - vec![Const::from(message.into()).into()], - )) - .run(self) - .expect("Into used as message") + let message = message.into(); + ReferenceError::constructor(&Value::undefined(), &[Value::from(message)], self) + .expect("Into used as message") } /// Throws a `ReferenceError` with the specified message. #[inline] - pub fn throw_reference_error(&mut self, message: M) -> Result + pub fn throw_reference_error(&self, message: M) -> Result where M: Into>, { @@ -414,21 +395,18 @@ impl Context { /// Constructs a `SyntaxError` with the specified message. #[inline] - pub fn construct_syntax_error(&mut self, message: M) -> Value + pub fn construct_syntax_error(&self, message: M) -> Value where M: Into>, { - New::from(Call::new( - Identifier::from("SyntaxError"), - vec![Const::from(message.into()).into()], - )) - .run(self) - .expect("Into used as message") + let message = message.into(); + SyntaxError::constructor(&Value::undefined(), &[Value::from(message)], self) + .expect("Into used as message") } /// Throws a `SyntaxError` with the specified message. #[inline] - pub fn throw_syntax_error(&mut self, message: M) -> Result + pub fn throw_syntax_error(&self, message: M) -> Result where M: Into>, { @@ -436,33 +414,27 @@ impl Context { } /// Constructs a `EvalError` with the specified message. - pub fn construct_eval_error(&mut self, message: M) -> Value + pub fn construct_eval_error(&self, message: M) -> Value where M: Into>, { - New::from(Call::new( - Identifier::from("EvalError"), - vec![Const::from(message.into()).into()], - )) - .run(self) - .expect("Into used as message") + let message = message.into(); + EvalError::constructor(&Value::undefined(), &[Value::from(message)], self) + .expect("Into used as message") } /// Constructs a `URIError` with the specified message. - pub fn construct_uri_error(&mut self, message: M) -> Value + pub fn construct_uri_error(&self, message: M) -> Value where M: Into>, { - New::from(Call::new( - Identifier::from("URIError"), - vec![Const::from(message.into()).into()], - )) - .run(self) - .expect("Into used as message") + let message = message.into(); + UriError::constructor(&Value::undefined(), &[Value::from(message)], self) + .expect("Into used as message") } /// Throws a `EvalError` with the specified message. - pub fn throw_eval_error(&mut self, message: M) -> Result + pub fn throw_eval_error(&self, message: M) -> Result where M: Into>, { @@ -470,7 +442,7 @@ impl Context { } /// Throws a `URIError` with the specified message. - pub fn throw_uri_error(&mut self, message: M) -> Result + pub fn throw_uri_error(&self, message: M) -> Result where M: Into>, { @@ -479,7 +451,7 @@ impl Context { /// Utility to create a function Value for Function Declarations, Arrow Functions or Function Expressions pub(crate) fn create_function( - &mut self, + &self, params: P, body: B, flags: FunctionFlags, @@ -500,7 +472,7 @@ impl Context { flags, body: RcStatementList::from(body.into()), params, - environment: self.realm.environment.get_current_environment().clone(), + environment: self.realm.environment.borrow().get_current_environment(), }; let new_func = Object::function(func, function_prototype); @@ -518,7 +490,7 @@ impl Context { /// Create a new builin function. pub fn create_builtin_function( - &mut self, + &self, name: &str, length: usize, body: NativeFunction, @@ -546,7 +518,7 @@ impl Context { /// Register a global function. #[inline] pub fn register_global_function( - &mut self, + &self, name: &str, length: usize, body: NativeFunction, @@ -565,7 +537,7 @@ impl Context { /// This is useful for the spread operator, for any other object an `Err` is returned /// TODO: Not needed for spread of arrays. Check in the future for Map and remove if necessary pub(crate) fn extract_array_properties( - &mut self, + &self, value: &Value, ) -> Result, ()>> { if let Value::Object(ref x) = value { @@ -588,8 +560,8 @@ impl Context { array.as_object().expect("object").set_prototype_instance( self.realm() .environment - .get_binding_value("Array") - .expect("Array was not initialized") + .borrow() + .get_binding_value("Array", self)? .get_field(PROTOTYPE, self)?, ); array.set_field(0, key, self)?; @@ -609,22 +581,24 @@ impl Context { /// #[inline] - pub(crate) fn has_property(&self, obj: &Value, key: &PropertyKey) -> bool { + pub(crate) fn has_property(&self, obj: &Value, key: &PropertyKey) -> Result { if let Some(obj) = obj.as_object() { - obj.has_property(key) + obj.has_property(key, self) } else { - false + Ok(false) } } #[inline] - pub(crate) fn set_value(&mut self, node: &Node, value: Value) -> Result { + pub(crate) fn set_value(&self, node: &Node, value: Value) -> Result { match node { Node::Identifier(ref name) => { - self.realm - .environment - .set_mutable_binding(name.as_ref(), value.clone(), true) - .map_err(|e| e.to_error(self))?; + self.realm.environment.borrow().set_mutable_binding( + name.as_ref(), + value.clone(), + true, + self, + )?; Ok(value) } Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node @@ -654,7 +628,7 @@ impl Context { /// context.register_global_class::(); /// ``` #[inline] - pub fn register_global_class(&mut self) -> Result<()> + pub fn register_global_class(&self) -> Result<()> where T: Class, { @@ -687,7 +661,7 @@ impl Context { /// context.register_global_property("myObjectProperty", object, Attribute::all()); /// ``` #[inline] - pub fn register_global_property(&mut self, key: K, value: V, attribute: Attribute) + pub fn register_global_property(&self, key: K, value: V, attribute: Attribute) where K: Into, V: Into, diff --git a/boa/src/environment/declarative_environment_record.rs b/boa/src/environment/declarative_environment_record.rs index 7d585b739a4..a90e72814d6 100644 --- a/boa/src/environment/declarative_environment_record.rs +++ b/boa/src/environment/declarative_environment_record.rs @@ -5,14 +5,13 @@ //! A declarative Environment Record binds the set of identifiers defined by the declarations contained within its scope. //! More info: [ECMA-262 sec-declarative-environment-records](https://tc39.es/ecma262/#sec-declarative-environment-records) -use super::ErrorKind; use crate::{ environment::{ environment_record_trait::EnvironmentRecordTrait, lexical_environment::{Environment, EnvironmentType}, }, gc::{Finalize, Trace}, - Value, + Context, Result, Value, }; use rustc_hash::FxHashMap; @@ -38,8 +37,8 @@ pub struct DeclarativeEnvironmentRecord { } impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { - fn has_binding(&self, name: &str) -> bool { - self.env_rec.contains_key(name) + fn has_binding(&self, name: &str, _context: &Context) -> Result { + Ok(self.env_rec.contains_key(name)) } fn create_mutable_binding( @@ -47,7 +46,8 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + _context: &Context, + ) -> Result<()> { if !allow_name_reuse { assert!( !self.env_rec.contains_key(&name), @@ -68,7 +68,12 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { Ok(()) } - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + _context: &Context, + ) -> Result<()> { assert!( !self.env_rec.contains_key(&name), "Identifier {} has already been declared", @@ -87,7 +92,7 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { Ok(()) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn initialize_binding(&mut self, name: &str, value: Value, _context: &Context) -> Result<()> { if let Some(ref mut record) = self.env_rec.get_mut(name) { if record.value.is_none() { record.value = Some(value); @@ -103,65 +108,67 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { name: &str, value: Value, mut strict: bool, - ) -> Result<(), ErrorKind> { + context: &Context, + ) -> Result<()> { if self.env_rec.get(name).is_none() { if strict { - return Err(ErrorKind::new_reference_error(format!( - "{} not found", - name - ))); + return Err(context.construct_reference_error(format!("{} not found", name))); } - self.create_mutable_binding(name.to_owned(), true, false)?; - self.initialize_binding(name, value)?; + self.create_mutable_binding(name.to_owned(), true, false, context)?; + self.initialize_binding(name, value, context)?; return Ok(()); } - let record: &mut DeclarativeEnvironmentRecordBinding = self.env_rec.get_mut(name).unwrap(); - if record.strict { - strict = true + let mut no_reference = false; + let mut cannot_mutate = false; + { + let record: &mut DeclarativeEnvironmentRecordBinding = + self.env_rec.get_mut(name).unwrap(); + if record.strict { + strict = true + } + if record.value.is_none() { + no_reference = true; + } else if record.mutable { + record.value = Some(value); + } else if strict { + cannot_mutate = true; + } } - if record.value.is_none() { - return Err(ErrorKind::new_reference_error(format!( - "{} has not been initialized", - name - ))); + if no_reference { + return Err( + context.construct_reference_error(format!("{} has not been initialized", name)) + ); } - if record.mutable { - record.value = Some(value); - } else if strict { - return Err(ErrorKind::new_type_error(format!( - "Cannot mutate an immutable binding {}", - name - ))); + if cannot_mutate { + return Err(context + .construct_type_error(format!("Cannot mutate an immutable binding {}", name))); } Ok(()) } - fn get_binding_value(&self, name: &str, _strict: bool) -> Result { + fn get_binding_value(&self, name: &str, _strict: bool, context: &Context) -> Result { if let Some(binding) = self.env_rec.get(name) { if let Some(ref val) = binding.value { Ok(val.clone()) } else { - Err(ErrorKind::new_reference_error(format!( - "{} is an uninitialized binding", - name - ))) + context.throw_reference_error(format!("{} is an uninitialized binding", name)) } } else { panic!("Cannot get binding value for {}", name); } } - fn delete_binding(&mut self, name: &str) -> bool { + fn delete_binding(&mut self, name: &str, _context: &Context) -> Result { match self.env_rec.get(name) { Some(binding) => { if binding.can_delete { self.env_rec.remove(name); - true + Ok(true) } else { - false + Ok(false) } } None => panic!("env_rec has no binding for {}", name), @@ -172,7 +179,7 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { false } - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, _context: &Context) -> Result { Ok(Value::undefined()) } @@ -180,8 +187,8 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { false } - fn with_base_object(&self) -> Value { - Value::undefined() + fn with_base_object(&self, _context: &Context) -> Result { + Ok(Value::undefined()) } fn get_outer_environment(&self) -> Option { diff --git a/boa/src/environment/environment_record_trait.rs b/boa/src/environment/environment_record_trait.rs index 1cf0243121b..538823c8dfa 100644 --- a/boa/src/environment/environment_record_trait.rs +++ b/boa/src/environment/environment_record_trait.rs @@ -8,21 +8,20 @@ //! //! There are 5 Environment record kinds. They all have methods in common, these are implemented as a the `EnvironmentRecordTrait` //! -use super::ErrorKind; use crate::{ environment::lexical_environment::{Environment, EnvironmentType}, gc::{Finalize, Trace}, - Value, + Context, Result, Value, }; use std::fmt::Debug; /// /// -/// In the ECMAScript specification Environment Records are hierachical and have a base class with abstract methods. +/// In the ECMAScript specification Environment Records are hierarchical and have a base class with abstract methods. /// In this implementation we have a trait which represents the behaviour of all `EnvironmentRecord` types. pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { /// Determine if an Environment Record has a binding for the String value N. Return true if it does and false if it does not. - fn has_binding(&self, name: &str) -> bool; + fn has_binding(&self, name: &str, context: &Context) -> Result; /// Create a new but uninitialized mutable binding in an Environment Record. The String value N is the text of the bound name. /// If the Boolean argument deletion is true the binding may be subsequently deleted. @@ -30,24 +29,30 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { /// * `allow_name_reuse` - specifies whether or not reusing binding names is allowed. /// /// Most variable names cannot be reused, but functions in JavaScript are allowed to have multiple - /// paraments with the same name. + /// parameters with the same name. fn create_mutable_binding( &mut self, name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind>; + context: &Context, + ) -> Result<()>; /// Create a new but uninitialized immutable binding in an Environment Record. /// The String value N is the text of the bound name. /// If strict is true then attempts to set it after it has been initialized will always throw an exception, /// regardless of the strict mode setting of operations that reference that binding. - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind>; + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + context: &Context, + ) -> Result<()>; /// Set the value of an already existing but uninitialized binding in an Environment Record. /// The String value N is the text of the bound name. /// V is the value for the binding and is a value of any ECMAScript language type. - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind>; + fn initialize_binding(&mut self, name: &str, value: Value, context: &Context) -> Result<()>; /// Set the value of an already existing mutable binding in an Environment Record. /// The String value `name` is the text of the bound name. @@ -58,26 +63,27 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind>; + context: &Context, + ) -> Result<()>; /// Returns the value of an already existing binding from an Environment Record. /// The String value N is the text of the bound name. /// S is used to identify references originating in strict mode code or that /// otherwise require strict mode reference semantics. - fn get_binding_value(&self, name: &str, strict: bool) -> Result; + fn get_binding_value(&self, name: &str, strict: bool, context: &Context) -> Result; /// Delete a binding from an Environment Record. /// The String value name is the text of the bound name. /// If a binding for name exists, remove the binding and return true. /// If the binding exists but cannot be removed return false. If the binding does not exist return true. - fn delete_binding(&mut self, name: &str) -> bool; + fn delete_binding(&mut self, name: &str, context: &Context) -> Result; /// Determine if an Environment Record establishes a this binding. /// Return true if it does and false if it does not. fn has_this_binding(&self) -> bool; /// Return the `this` binding from the environment - fn get_this_binding(&self) -> Result; + fn get_this_binding(&self, context: &Context) -> Result; /// Determine if an Environment Record establishes a super method binding. /// Return true if it does and false if it does not. @@ -85,7 +91,7 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { /// If this Environment Record is associated with a with statement, return the with object. /// Otherwise, return undefined. - fn with_base_object(&self) -> Value; + fn with_base_object(&self, context: &Context) -> Result; /// Get the next environment up fn get_outer_environment(&self) -> Option; diff --git a/boa/src/environment/function_environment_record.rs b/boa/src/environment/function_environment_record.rs index 441c15c1844..e78325c0210 100644 --- a/boa/src/environment/function_environment_record.rs +++ b/boa/src/environment/function_environment_record.rs @@ -8,7 +8,6 @@ //! from within the function. //! More info: -use super::ErrorKind; use crate::{ environment::{ declarative_environment_record::DeclarativeEnvironmentRecordBinding, @@ -17,7 +16,7 @@ use crate::{ }, gc::{empty_trace, Finalize, Trace}, object::GcObject, - Value, + Context, Result, Value, }; use rustc_hash::FxHashMap; @@ -61,16 +60,16 @@ pub struct FunctionEnvironmentRecord { } impl FunctionEnvironmentRecord { - pub fn bind_this_value(&mut self, value: Value) -> Result { + pub fn bind_this_value(&mut self, value: Value, context: &Context) -> Result { match self.this_binding_status { // You can not bind an arrow function, their `this` value comes from the lexical scope above BindingStatus::Lexical => { panic!("Cannot bind to an arrow function!"); } // You can not bind a function twice - BindingStatus::Initialized => Err(ErrorKind::new_reference_error( - "Cannot bind to an initialised function!", - )), + BindingStatus::Initialized => { + context.throw_reference_error("Cannot bind to an initialised function!") + } BindingStatus::Uninitialized => { self.this_value = value.clone(); @@ -94,8 +93,8 @@ impl FunctionEnvironmentRecord { } impl EnvironmentRecordTrait for FunctionEnvironmentRecord { - fn has_binding(&self, name: &str) -> bool { - self.env_rec.contains_key(name) + fn has_binding(&self, name: &str, _context: &Context) -> Result { + Ok(self.env_rec.contains_key(name)) } fn create_mutable_binding( @@ -103,7 +102,8 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + _context: &Context, + ) -> Result<()> { if !allow_name_reuse { assert!( !self.env_rec.contains_key(&name), @@ -124,20 +124,25 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { Ok(()) } - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, context: &Context) -> Result { match self.this_binding_status { BindingStatus::Lexical => { panic!("There is no this for a lexical function record"); } - BindingStatus::Uninitialized => Err(ErrorKind::new_reference_error( - "Uninitialised binding for this function", - )), + BindingStatus::Uninitialized => { + context.throw_reference_error("Uninitialised binding for this function") + } BindingStatus::Initialized => Ok(self.this_value.clone()), } } - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + _context: &Context, + ) -> Result<()> { assert!( !self.env_rec.contains_key(&name), "Identifier {} has already been declared", @@ -156,7 +161,7 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { Ok(()) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn initialize_binding(&mut self, name: &str, value: Value, _context: &Context) -> Result<()> { if let Some(ref mut record) = self.env_rec.get_mut(name) { if record.value.is_none() { record.value = Some(value); @@ -172,17 +177,15 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { name: &str, value: Value, mut strict: bool, - ) -> Result<(), ErrorKind> { + context: &Context, + ) -> Result<()> { if self.env_rec.get(name).is_none() { if strict { - return Err(ErrorKind::new_reference_error(format!( - "{} not found", - name - ))); + return Err(context.construct_reference_error(format!("{} not found", name))); } - self.create_mutable_binding(name.to_owned(), true, false)?; - self.initialize_binding(name, value)?; + self.create_mutable_binding(name.to_owned(), true, false, context)?; + self.initialize_binding(name, value, context)?; return Ok(()); } @@ -191,46 +194,40 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { strict = true } if record.value.is_none() { - return Err(ErrorKind::new_reference_error(format!( - "{} has not been initialized", - name - ))); + return Err( + context.construct_reference_error(format!("{} has not been initialized", name)) + ); } if record.mutable { record.value = Some(value); } else if strict { - return Err(ErrorKind::new_type_error(format!( - "Cannot mutate an immutable binding {}", - name - ))); + return Err(context + .construct_type_error(format!("Cannot mutate an immutable binding {}", name))); } Ok(()) } - fn get_binding_value(&self, name: &str, _strict: bool) -> Result { + fn get_binding_value(&self, name: &str, _strict: bool, context: &Context) -> Result { if let Some(binding) = self.env_rec.get(name) { if let Some(ref val) = binding.value { Ok(val.clone()) } else { - Err(ErrorKind::new_reference_error(format!( - "{} is an uninitialized binding", - name - ))) + context.throw_reference_error(format!("{} is an uninitialized binding", name)) } } else { panic!("Cannot get binding value for {}", name); } } - fn delete_binding(&mut self, name: &str) -> bool { + fn delete_binding(&mut self, name: &str, _context: &Context) -> Result { match self.env_rec.get(name) { Some(binding) => { if binding.can_delete { self.env_rec.remove(name); - true + Ok(true) } else { - false + Ok(false) } } None => panic!("env_rec has no binding for {}", name), @@ -249,8 +246,8 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { !matches!(self.this_binding_status, BindingStatus::Lexical) } - fn with_base_object(&self) -> Value { - Value::undefined() + fn with_base_object(&self, _context: &Context) -> Result { + Ok(Value::undefined()) } fn get_outer_environment(&self) -> Option { diff --git a/boa/src/environment/global_environment_record.rs b/boa/src/environment/global_environment_record.rs index e9da576e8b3..ef639c23af4 100644 --- a/boa/src/environment/global_environment_record.rs +++ b/boa/src/environment/global_environment_record.rs @@ -7,7 +7,6 @@ //! that occur within a Script. //! More info: -use super::ErrorKind; use crate::{ environment::{ declarative_environment_record::DeclarativeEnvironmentRecord, @@ -17,7 +16,7 @@ use crate::{ }, gc::{Finalize, Trace}, property::{Attribute, DataDescriptor}, - Value, + Context, Result, Value, }; use rustc_hash::FxHashSet; @@ -34,45 +33,47 @@ impl GlobalEnvironmentRecord { self.var_names.contains(name) } - pub fn has_lexical_declaration(&self, name: &str) -> bool { - self.declarative_record.has_binding(name) + pub fn has_lexical_declaration(&self, name: &str, context: &Context) -> Result { + self.declarative_record.has_binding(name, context) } - pub fn has_restricted_global_property(&self, name: &str) -> bool { + pub fn has_restricted_global_property(&self, name: &str, context: &Context) -> Result { let global_object = &self.object_record.bindings; - let existing_prop = global_object.get_property(name); + let existing_prop = global_object.get_property(name, context)?; match existing_prop { Some(desc) => { if desc.configurable() { - return false; + return Ok(false); } - true + Ok(true) } - None => false, + None => Ok(false), } } - pub fn can_declare_global_var(&self, name: &str) -> bool { + pub fn can_declare_global_var(&self, name: &str, context: &Context) -> Result { let global_object = &self.object_record.bindings; - if global_object.has_field(name) { - true + if global_object.has_field(name, context)? { + Ok(true) } else { - global_object.is_extensible() + global_object.is_extensible(context) } } - pub fn can_declare_global_function(&self, name: &str) -> bool { + pub fn can_declare_global_function(&self, name: &str, context: &Context) -> Result { let global_object = &self.object_record.bindings; - let existing_prop = global_object.get_property(name); + let existing_prop = global_object.get_property(name, context)?; match existing_prop { Some(prop) => { if prop.configurable() { - true + Ok(true) } else { - prop.is_data_descriptor() && prop.attributes().writable() && prop.enumerable() + Ok(prop.is_data_descriptor() + && prop.attributes().writable() + && prop.enumerable()) } } - None => global_object.is_extensible(), + None => global_object.is_extensible(context), } } @@ -80,14 +81,15 @@ impl GlobalEnvironmentRecord { &mut self, name: String, deletion: bool, - ) -> Result<(), ErrorKind> { + context: &Context, + ) -> Result<()> { let obj_rec = &mut self.object_record; let global_object = &obj_rec.bindings; - let has_property = global_object.has_field(name.as_str()); - let extensible = global_object.is_extensible(); + let has_property = global_object.has_field(name.as_str(), context)?; + let extensible = global_object.is_extensible(context)?; if !has_property && extensible { - obj_rec.create_mutable_binding(name.clone(), deletion, false)?; - obj_rec.initialize_binding(&name, Value::undefined())?; + obj_rec.create_mutable_binding(name.clone(), deletion, false, context)?; + obj_rec.initialize_binding(&name, Value::undefined(), context)?; } let var_declared_names = &mut self.var_names; @@ -97,9 +99,15 @@ impl GlobalEnvironmentRecord { Ok(()) } - pub fn create_global_function_binding(&mut self, name: &str, value: Value, deletion: bool) { + pub fn create_global_function_binding( + &mut self, + name: &str, + value: Value, + deletion: bool, + context: &Context, + ) -> Result<()> { let global_object = &mut self.object_record.bindings; - let existing_prop = global_object.get_property(name); + let existing_prop = global_object.get_property(name, context)?; let desc = match existing_prop { Some(desc) if desc.configurable() => DataDescriptor::new(value, Attribute::empty()), Some(_) => { @@ -116,19 +124,20 @@ impl GlobalEnvironmentRecord { .as_object() .expect("global object") .insert(name, desc); + Ok(()) } } impl EnvironmentRecordTrait for GlobalEnvironmentRecord { - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, _context: &Context) -> Result { Ok(self.global_this_binding.clone()) } - fn has_binding(&self, name: &str) -> bool { - if self.declarative_record.has_binding(name) { - return true; + fn has_binding(&self, name: &str, context: &Context) -> Result { + if self.declarative_record.has_binding(name, context)? { + return Ok(true); } - self.object_record.has_binding(name) + self.object_record.has_binding(name, context) } fn create_mutable_binding( @@ -136,40 +145,46 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { - if !allow_name_reuse && self.declarative_record.has_binding(&name) { - return Err(ErrorKind::new_type_error(format!( - "Binding already exists for {}", - name - ))); + context: &Context, + ) -> Result<()> { + if !allow_name_reuse && self.declarative_record.has_binding(&name, context)? { + return Err( + context.construct_type_error(format!("Binding already exists for {}", name)) + ); } self.declarative_record - .create_mutable_binding(name, deletion, allow_name_reuse) + .create_mutable_binding(name, deletion, allow_name_reuse, context) } - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind> { - if self.declarative_record.has_binding(&name) { - return Err(ErrorKind::new_type_error(format!( - "Binding already exists for {}", - name - ))); + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + context: &Context, + ) -> Result<()> { + if self.declarative_record.has_binding(&name, context)? { + return Err( + context.construct_type_error(format!("Binding already exists for {}", name)) + ); } self.declarative_record - .create_immutable_binding(name, strict) + .create_immutable_binding(name, strict, context) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { - if self.declarative_record.has_binding(&name) { - return self.declarative_record.initialize_binding(name, value); + fn initialize_binding(&mut self, name: &str, value: Value, context: &Context) -> Result<()> { + if self.declarative_record.has_binding(&name, context)? { + return self + .declarative_record + .initialize_binding(name, value, context); } assert!( - self.object_record.has_binding(name), + self.object_record.has_binding(name, context)?, "Binding must be in object_record" ); - self.object_record.initialize_binding(name, value) + self.object_record.initialize_binding(name, value, context) } fn set_mutable_binding( @@ -177,39 +192,43 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { - if self.declarative_record.has_binding(&name) { + context: &Context, + ) -> Result<()> { + if self.declarative_record.has_binding(&name, context)? { return self .declarative_record - .set_mutable_binding(name, value, strict); + .set_mutable_binding(name, value, strict, context); } - self.object_record.set_mutable_binding(name, value, strict) + self.object_record + .set_mutable_binding(name, value, strict, context) } - fn get_binding_value(&self, name: &str, strict: bool) -> Result { - if self.declarative_record.has_binding(&name) { - return self.declarative_record.get_binding_value(name, strict); + fn get_binding_value(&self, name: &str, strict: bool, context: &Context) -> Result { + if self.declarative_record.has_binding(&name, context)? { + return self + .declarative_record + .get_binding_value(name, strict, context); } - self.object_record.get_binding_value(name, strict) + self.object_record.get_binding_value(name, strict, context) } - fn delete_binding(&mut self, name: &str) -> bool { - if self.declarative_record.has_binding(&name) { - return self.declarative_record.delete_binding(name); + fn delete_binding(&mut self, name: &str, context: &Context) -> Result { + if self.declarative_record.has_binding(&name, context)? { + return self.declarative_record.delete_binding(name, context); } let global: &Value = &self.object_record.bindings; - if global.has_field(name) { - let status = self.object_record.delete_binding(name); + if global.has_field(name, context)? { + let status = self.object_record.delete_binding(name, context)?; if status { let var_names = &mut self.var_names; if var_names.contains(name) { var_names.remove(name); - return status; + return Ok(status); } } } - true + Ok(true) } fn has_this_binding(&self) -> bool { @@ -220,8 +239,8 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { false } - fn with_base_object(&self) -> Value { - Value::undefined() + fn with_base_object(&self, _context: &Context) -> Result { + Ok(Value::undefined()) } fn get_outer_environment(&self) -> Option { diff --git a/boa/src/environment/lexical_environment.rs b/boa/src/environment/lexical_environment.rs index 07427ba9767..c34fb6609f3 100644 --- a/boa/src/environment/lexical_environment.rs +++ b/boa/src/environment/lexical_environment.rs @@ -5,7 +5,6 @@ //! The following operations are used to operate upon lexical environments //! This is the entrypoint to lexical environments. -use super::ErrorKind; use crate::{ environment::{ declarative_environment_record::DeclarativeEnvironmentRecord, @@ -15,10 +14,11 @@ use crate::{ object_environment_record::ObjectEnvironmentRecord, }, object::GcObject, - BoaProfiler, Value, + BoaProfiler, Context, Result, Value, }; use gc::{Gc, GcCell}; use rustc_hash::{FxHashMap, FxHashSet}; +use std::cell::RefCell; use std::{collections::VecDeque, error, fmt}; /// Environments are wrapped in a Box and then in a GC wrapper @@ -45,7 +45,7 @@ pub enum VariableScope { #[derive(Debug, Clone)] pub struct LexicalEnvironment { - environment_stack: VecDeque, + environment_stack: RefCell>, } /// An error that occurred during lexing or compiling of the source input. @@ -83,59 +83,67 @@ impl LexicalEnvironment { pub fn new(global: Value) -> Self { let _timer = BoaProfiler::global().start_event("LexicalEnvironment::new", "env"); let global_env = new_global_environment(global.clone(), global); - let mut lexical_env = Self { - environment_stack: VecDeque::new(), + let lexical_env = Self { + environment_stack: RefCell::new(VecDeque::new()), }; // lexical_env.push(global_env); - lexical_env.environment_stack.push_back(global_env); + lexical_env + .environment_stack + .borrow_mut() + .push_back(global_env); lexical_env } - pub fn push(&mut self, env: Environment) { - let current_env: Environment = self.get_current_environment().clone(); + pub fn push(&self, env: Environment) { + let current_env: Environment = self.get_current_environment(); env.borrow_mut().set_outer_environment(current_env); - self.environment_stack.push_back(env); - } - - pub fn pop(&mut self) -> Option { - self.environment_stack.pop_back() + self.environment_stack.borrow_mut().push_back(env); } - pub fn environments(&self) -> impl Iterator { - self.environment_stack.iter().rev() + pub fn pop(&self) -> Option { + self.environment_stack.borrow_mut().pop_back() } pub fn get_global_object(&self) -> Option { self.environment_stack + .borrow() .get(0) .expect("") .borrow() .get_global_object() } - pub fn get_this_binding(&self) -> Result { - self.environments() + pub fn get_this_binding(&self, context: &Context) -> Result { + Ok(self + .environment_stack + .borrow() + .iter() + .rev() .find(|env| env.borrow().has_this_binding()) - .map(|env| env.borrow().get_this_binding()) - .unwrap_or_else(|| Ok(Value::Undefined)) + .map(|env| env.borrow().get_this_binding(context)) + .transpose()? + .unwrap_or_else(Value::undefined)) } pub fn create_mutable_binding( - &mut self, + &self, name: String, deletion: bool, scope: VariableScope, - ) -> Result<(), ErrorKind> { + context: &Context, + ) -> Result<()> { match scope { VariableScope::Block => self .get_current_environment() .borrow_mut() - .create_mutable_binding(name, deletion, false), + .create_mutable_binding(name, deletion, false, context), VariableScope::Function => { // Find the first function or global environment (from the top of the stack) - let env = self - .environments() + let stack = &self.environment_stack.borrow(); + let env = stack + .iter() + .rev() .find(|env| { matches!( env.borrow().get_environment_type(), @@ -144,27 +152,30 @@ impl LexicalEnvironment { }) .expect("No function or global environment"); - env.borrow_mut() - .create_mutable_binding(name, deletion, false) + let mut env = env.borrow_mut(); + env.create_mutable_binding(name, deletion, false, context) } } } pub fn create_immutable_binding( - &mut self, + &self, name: String, deletion: bool, scope: VariableScope, - ) -> Result<(), ErrorKind> { + context: &Context, + ) -> Result<()> { match scope { VariableScope::Block => self .get_current_environment() .borrow_mut() - .create_immutable_binding(name, deletion), + .create_immutable_binding(name, deletion, context), VariableScope::Function => { // Find the first function or global environment (from the top of the stack) - let env = self - .environments() + let stack = self.environment_stack.borrow(); + let env = stack + .iter() + .rev() .find(|env| { matches!( env.borrow().get_environment_type(), @@ -173,81 +184,102 @@ impl LexicalEnvironment { }) .expect("No function or global environment"); - env.borrow_mut().create_immutable_binding(name, deletion) + let res = env + .borrow_mut() + .create_immutable_binding(name, deletion, context); + res } } } pub fn set_mutable_binding( - &mut self, + &self, name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { + context: &Context, + ) -> Result<()> { // Find the first environment which has the given binding - let env = self - .environments() - .find(|env| env.borrow().has_binding(name)); + let stack = &self.environment_stack.borrow(); + let find_environment_with_binding = || -> Result> { + for env in stack.iter().rev() { + if env.borrow().has_binding(name, context)? { + return Ok(Some(env)); + } + } + Ok(None) + }; + let env = find_environment_with_binding()?; let env = if let Some(env) = env { env } else { // global_env doesn't need has_binding to be satisfied in non strict mode - self.environment_stack - .get(0) - .expect("Environment stack underflow") + stack.get(0).expect("Environment stack underflow") }; - env.borrow_mut().set_mutable_binding(name, value, strict) + let res = env + .borrow_mut() + .set_mutable_binding(name, value, strict, context); + res } - pub fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + pub fn initialize_binding(&self, name: &str, value: Value, context: &Context) -> Result<()> { // Find the first environment which has the given binding - let env = self - .environments() - .find(|env| env.borrow().has_binding(name)); - + let stack = &self.environment_stack.borrow(); + let find_environment_with_binding = || -> Result> { + for env in stack.iter().rev() { + if env.borrow().has_binding(name, context)? { + return Ok(Some(env)); + } + } + Ok(None) + }; + let env = find_environment_with_binding()?; let env = if let Some(env) = env { env } else { // global_env doesn't need has_binding to be satisfied in non strict mode - self.environment_stack - .get(0) - .expect("Environment stack underflow") + stack.get(0).expect("Environment stack underflow") }; - env.borrow_mut().initialize_binding(name, value) - } - - /// get_current_environment_ref is used when you only need to borrow the environment - /// (you only need to add a new variable binding, or you want to fetch a value) - pub fn get_current_environment_ref(&self) -> &Environment { - self.environment_stack - .back() - .expect("Could not get current environment") + let res = env.borrow_mut().initialize_binding(name, value, context); + res } - /// When neededing to clone an environment (linking it with another environnment) + /// When need to clone an environment (linking it with another environment) /// cloning is more suited. The GC will remove the env once nothing is linking to it anymore - pub fn get_current_environment(&mut self) -> &mut Environment { + pub fn get_current_environment(&self) -> Environment { self.environment_stack - .back_mut() + .borrow() + .back() + .cloned() .expect("Could not get mutable reference to back object") } - pub fn has_binding(&self, name: &str) -> bool { - self.environments() - .any(|env| env.borrow().has_binding(name)) + pub fn has_binding(&self, name: &str, context: &Context) -> Result { + for e in self.environment_stack.borrow().iter().rev() { + if e.borrow().has_binding(name, context)? { + return Ok(true); + } + } + Ok(false) } - pub fn get_binding_value(&self, name: &str) -> Result { - self.environments() - .find(|env| env.borrow().has_binding(name)) - .map(|env| env.borrow().get_binding_value(name, false)) - .unwrap_or_else(|| { - Err(ErrorKind::new_reference_error(format!( - "{} is not defined", - name - ))) - }) + pub fn get_binding_value(&self, name: &str, context: &Context) -> Result { + let stack = &self.environment_stack.borrow(); + let find_environment_with_binding = || -> Result> { + for env in stack.iter().rev() { + if env.borrow().has_binding(name, context)? { + return Ok(Some(env)); + } + } + Ok(None) + }; + let env = find_environment_with_binding()?; + if let Some(env) = env { + env.borrow().get_binding_value(name, false, context) + } else { + context.throw_reference_error(format!("{} is not defined", name)) + } } } @@ -267,6 +299,7 @@ pub fn new_function_environment( outer: Option, binding_status: BindingStatus, new_target: Value, + context: &Context, ) -> Environment { let mut func_env = FunctionEnvironmentRecord { env_rec: FxHashMap::default(), @@ -279,7 +312,7 @@ pub fn new_function_environment( }; // If a `this` value has been passed, bind it to the environment if let Some(v) = this { - func_env.bind_this_value(v).unwrap(); + func_env.bind_this_value(v, context).unwrap(); } Gc::new(GcCell::new(Box::new(func_env))) } diff --git a/boa/src/environment/mod.rs b/boa/src/environment/mod.rs index ceb1773c38a..8070bd0304d 100644 --- a/boa/src/environment/mod.rs +++ b/boa/src/environment/mod.rs @@ -1,4 +1,4 @@ -//! Environment handling, lexical, object, function and declaritive records +//! Environment handling, lexical, object, function and declarative records pub mod declarative_environment_record; pub mod environment_record_trait; @@ -6,35 +6,3 @@ pub mod function_environment_record; pub mod global_environment_record; pub mod lexical_environment; pub mod object_environment_record; - -#[derive(Debug)] -pub enum ErrorKind { - ReferenceError(Box), - TypeError(Box), -} - -use crate::value::Value; -use crate::Context; - -impl ErrorKind { - pub fn to_error(&self, ctx: &mut Context) -> Value { - match self { - ErrorKind::ReferenceError(msg) => ctx.construct_reference_error(msg.clone()), - ErrorKind::TypeError(msg) => ctx.construct_type_error(msg.clone()), - } - } - - pub fn new_reference_error(msg: M) -> Self - where - M: Into>, - { - Self::ReferenceError(msg.into()) - } - - pub fn new_type_error(msg: M) -> Self - where - M: Into>, - { - Self::TypeError(msg.into()) - } -} diff --git a/boa/src/environment/object_environment_record.rs b/boa/src/environment/object_environment_record.rs index 1c5639fc737..1359caf2056 100644 --- a/boa/src/environment/object_environment_record.rs +++ b/boa/src/environment/object_environment_record.rs @@ -6,7 +6,6 @@ //! Property keys that are not strings in the form of an `IdentifierName` are not included in the set of bound identifiers. //! More info: [Object Records](https://tc39.es/ecma262/#sec-object-environment-records) -use super::*; use crate::property::PropertyDescriptor; use crate::{ environment::{ @@ -15,7 +14,7 @@ use crate::{ }, gc::{Finalize, Trace}, property::{Attribute, DataDescriptor}, - Value, + Context, Result, Value, }; #[derive(Debug, Trace, Finalize, Clone)] @@ -26,14 +25,14 @@ pub struct ObjectEnvironmentRecord { } impl EnvironmentRecordTrait for ObjectEnvironmentRecord { - fn has_binding(&self, name: &str) -> bool { - if self.bindings.has_field(name) { + fn has_binding(&self, name: &str, context: &Context) -> Result { + if self.bindings.has_field(name, context)? { if self.with_environment { // TODO: implement unscopables } - true + Ok(true) } else { - false + Ok(false) } } @@ -42,7 +41,8 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { name: String, deletion: bool, _allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + _context: &Context, + ) -> Result<()> { // TODO: could save time here and not bother generating a new undefined object, // only for it to be replace with the real value later. We could just add the name to a Vector instead let bindings = &mut self.bindings; @@ -56,16 +56,21 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { Ok(()) } - fn create_immutable_binding(&mut self, _name: String, _strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + _name: String, + _strict: bool, + _context: &Context, + ) -> Result<()> { Ok(()) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn initialize_binding(&mut self, name: &str, value: Value, context: &Context) -> Result<()> { // We should never need to check if a binding has been created, // As all calls to create_mutable_binding are followed by initialized binding // The below is just a check. - debug_assert!(self.has_binding(&name)); - self.set_mutable_binding(name, value, false) + debug_assert!(self.has_binding(&name, context)?); + self.set_mutable_binding(name, value, false, context) } fn set_mutable_binding( @@ -73,8 +78,10 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { + _context: &Context, + ) -> Result<()> { debug_assert!(value.is_object() || value.is_function()); + let mut property = DataDescriptor::new(value, Attribute::ENUMERABLE); property.set_configurable(strict); self.bindings @@ -84,32 +91,29 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { Ok(()) } - fn get_binding_value(&self, name: &str, strict: bool) -> Result { - if self.bindings.has_field(name) { - match self.bindings.get_property(name) { + fn get_binding_value(&self, name: &str, strict: bool, context: &Context) -> Result { + if self.bindings.has_field(name, context)? { + match self.bindings.get_property(name, context)? { Some(PropertyDescriptor::Data(ref d)) => Ok(d.value()), _ => Ok(Value::undefined()), } } else if strict { - Err(ErrorKind::new_reference_error(format!( - "{} has no binding", - name - ))) + context.throw_reference_error(format!("{} has no binding", name)) } else { Ok(Value::undefined()) } } - fn delete_binding(&mut self, name: &str) -> bool { + fn delete_binding(&mut self, name: &str, _context: &Context) -> Result { self.bindings.remove_property(name); - true + Ok(true) } fn has_this_binding(&self) -> bool { false } - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, _context: &Context) -> Result { Ok(Value::undefined()) } @@ -117,14 +121,14 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { false } - fn with_base_object(&self) -> Value { + fn with_base_object(&self, _context: &Context) -> Result { // Object Environment Records return undefined as their // WithBaseObject unless their withEnvironment flag is true. if self.with_environment { - return self.bindings.clone(); + return Ok(self.bindings.clone()); } - Value::undefined() + Ok(Value::undefined()) } fn get_outer_environment(&self) -> Option { diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 737de76461d..adb620fdca8 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -7,7 +7,7 @@ use crate::{Context, Result, Value}; pub trait Executable { /// Runs this executable in the given context. - fn run(&self, context: &mut Context) -> Result; + fn run(&self, context: &Context) -> Result; } #[derive(Debug, Eq, PartialEq)] diff --git a/boa/src/lib.rs b/boa/src/lib.rs index 0540130fc3a..21f2ac360ac 100644 --- a/boa/src/lib.rs +++ b/boa/src/lib.rs @@ -88,7 +88,7 @@ pub fn parse>(src: T, strict_mode: bool) -> StdResult>(context: &mut Context, src: T) -> String { +pub(crate) fn forward>(context: &Context, src: T) -> String { let src_bytes: &[u8] = src.as_ref(); // Setup executor @@ -100,13 +100,13 @@ pub(crate) fn forward>(context: &mut Context, src: T) -> String { context .throw_syntax_error(e.to_string()) .expect_err("interpreter.throw_syntax_error() did not return an error") - .display() + .display(context) ); } }; expr.run(context).map_or_else( - |e| format!("Uncaught {}", e.display()), - |v| v.display().to_string(), + |e| format!("Uncaught {}", e.display(context)), + |v| v.display(context).to_string(), ) } @@ -116,7 +116,7 @@ pub(crate) fn forward>(context: &mut Context, src: T) -> String { /// If the interpreter fails parsing an error value is returned instead (error object) #[allow(clippy::unit_arg, clippy::drop_copy)] #[cfg(test)] -pub(crate) fn forward_val>(context: &mut Context, src: T) -> Result { +pub(crate) fn forward_val>(context: &Context, src: T) -> Result { let main_timer = BoaProfiler::global().start_event("Main", "Main"); let src_bytes: &[u8] = src.as_ref(); @@ -140,9 +140,9 @@ pub(crate) fn forward_val>(context: &mut Context, src: T) -> Resu #[cfg(test)] pub(crate) fn exec>(src: T) -> String { let src_bytes: &[u8] = src.as_ref(); - - match Context::new().eval(src_bytes) { - Ok(value) => value.display().to_string(), - Err(error) => error.display().to_string(), + let mut context = Context::new(); + match context.eval(src_bytes) { + Ok(value) => value.display(&context).to_string(), + Err(error) => error.display(&context).to_string(), } } diff --git a/boa/src/object/gcobject.rs b/boa/src/object/gcobject.rs index 2ead7754280..5280c0da25a 100644 --- a/boa/src/object/gcobject.rs +++ b/boa/src/object/gcobject.rs @@ -115,7 +115,7 @@ impl GcObject { // // #[track_caller] - pub fn call(&self, this: &Value, args: &[Value], context: &mut Context) -> Result { + pub fn call(&self, this: &Value, args: &[Value], context: &Context) -> Result { let this_function_object = self.clone(); let f_body = if let Some(function) = self.borrow().as_function() { if function.is_callable() { @@ -150,32 +150,37 @@ impl GcObject { BindingStatus::Uninitialized }, Value::undefined(), + context, ); // Add argument bindings to the function environment for (i, param) in params.iter().enumerate() { // Rest Parameters if param.is_rest_param() { - function.add_rest_param(param, i, args, context, &local_env); + function.add_rest_param(param, i, args, context, &local_env)?; break; } let value = args.get(i).cloned().unwrap_or_else(Value::undefined); - function.add_arguments_to_environment(param, value, &local_env); + function + .add_arguments_to_environment(param, value, &local_env, context)?; } // Add arguments object - let arguments_obj = create_unmapped_arguments_object(args); - local_env - .borrow_mut() - .create_mutable_binding("arguments".to_string(), false, true) - .map_err(|e| e.to_error(context))?; - local_env - .borrow_mut() - .initialize_binding("arguments", arguments_obj) - .map_err(|e| e.to_error(context))?; - - context.realm_mut().environment.push(local_env); + let arguments_obj = create_unmapped_arguments_object(args, context)?; + local_env.borrow_mut().create_mutable_binding( + "arguments".to_string(), + false, + true, + context, + )?; + local_env.borrow_mut().initialize_binding( + "arguments", + arguments_obj, + context, + )?; + + context.realm().environment.borrow().push(local_env); FunctionBody::Ordinary(body.clone()) } @@ -192,7 +197,7 @@ impl GcObject { FunctionBody::BuiltInConstructor(func) => func(&Value::undefined(), args, context), FunctionBody::Ordinary(body) => { let result = body.run(context); - context.realm_mut().environment.pop(); + context.realm().environment.borrow().pop(); result } @@ -206,12 +211,7 @@ impl GcObject { /// Panics if the object is currently mutably borrowed. // #[track_caller] - pub fn construct( - &self, - args: &[Value], - new_target: Value, - context: &mut Context, - ) -> Result { + pub fn construct(&self, args: &[Value], new_target: Value, context: &Context) -> Result { let this_function_object = self.clone(); let body = if let Some(function) = self.borrow().as_function() { if function.is_constructable() { @@ -258,32 +258,37 @@ impl GcObject { BindingStatus::Uninitialized }, new_target.clone(), + context, ); // Add argument bindings to the function environment for (i, param) in params.iter().enumerate() { // Rest Parameters if param.is_rest_param() { - function.add_rest_param(param, i, args, context, &local_env); + function.add_rest_param(param, i, args, context, &local_env)?; break; } let value = args.get(i).cloned().unwrap_or_else(Value::undefined); - function.add_arguments_to_environment(param, value, &local_env); + function + .add_arguments_to_environment(param, value, &local_env, context)?; } // Add arguments object - let arguments_obj = create_unmapped_arguments_object(args); - local_env - .borrow_mut() - .create_mutable_binding("arguments".to_string(), false, true) - .map_err(|e| e.to_error(context))?; - local_env - .borrow_mut() - .initialize_binding("arguments", arguments_obj) - .map_err(|e| e.to_error(context))?; - - context.realm_mut().environment.push(local_env); + let arguments_obj = create_unmapped_arguments_object(args, context)?; + local_env.borrow_mut().create_mutable_binding( + "arguments".to_string(), + false, + true, + context, + )?; + local_env.borrow_mut().initialize_binding( + "arguments", + arguments_obj, + context, + )?; + + context.realm().environment.borrow().push(local_env); FunctionBody::Ordinary(body.clone()) } @@ -291,7 +296,7 @@ impl GcObject { } else { let name = self .get(&"name".into(), self.clone().into(), context)? - .display() + .display(context) .to_string(); return context.throw_type_error(format!("{} is not a constructor", name)); } @@ -305,8 +310,8 @@ impl GcObject { let _ = body.run(context); // local_env gets dropped here, its no longer needed - let binding = context.realm_mut().environment.get_this_binding(); - binding.map_err(|e| e.to_error(context)) + let env = &context.realm().environment.borrow(); + env.get_this_binding(context) } FunctionBody::BuiltInFunction(_) => unreachable!("Cannot have a function in construct"), } @@ -332,7 +337,7 @@ impl GcObject { /// [spec]: https://tc39.es/ecma262/#sec-ordinarytoprimitive pub(crate) fn ordinary_to_primitive( &self, - context: &mut Context, + context: &Context, hint: PreferredType, ) -> Result { // 1. Assert: Type(O) is Object. @@ -385,7 +390,7 @@ impl GcObject { } /// Converts an object to JSON, checking for reference cycles and throwing a TypeError if one is found - pub(crate) fn to_json(&self, context: &mut Context) -> Result { + pub(crate) fn to_json(&self, context: &Context) -> Result { let rec_limiter = RecursionLimiter::new(self); if rec_limiter.live { Err(context.construct_type_error("cyclic object value")) @@ -417,16 +422,16 @@ impl GcObject { } } - /// Convert the object to a `PropertyDescritptor` + /// Convert the object to a `PropertyDescriptor` /// /// # Panics /// /// Panics if the object is currently mutably borrowed. - pub fn to_property_descriptor(&self, context: &mut Context) -> Result { + pub fn to_property_descriptor(&self, context: &Context) -> Result { let mut attribute = Attribute::empty(); let enumerable_key = PropertyKey::from("enumerable"); - if self.has_property(&enumerable_key) + if self.has_property(&enumerable_key, context)? && self .get(&enumerable_key, self.clone().into(), context)? .to_boolean() @@ -435,7 +440,7 @@ impl GcObject { } let configurable_key = PropertyKey::from("configurable"); - if self.has_property(&configurable_key) + if self.has_property(&configurable_key, context)? && self .get(&configurable_key, self.clone().into(), context)? .to_boolean() @@ -445,13 +450,13 @@ impl GcObject { let mut value = None; let value_key = PropertyKey::from("value"); - if self.has_property(&value_key) { + if self.has_property(&value_key, context)? { value = Some(self.get(&value_key, self.clone().into(), context)?); } let mut has_writable = false; let writable_key = PropertyKey::from("writable"); - if self.has_property(&writable_key) { + if self.has_property(&writable_key, context)? { has_writable = true; if self .get(&writable_key, self.clone().into(), context)? @@ -463,7 +468,7 @@ impl GcObject { let mut get = None; let get_key = PropertyKey::from("get"); - if self.has_property(&get_key) { + if self.has_property(&get_key, context)? { let getter = self.get(&get_key, self.clone().into(), context)?; match getter { Value::Object(ref object) if object.is_callable() => { @@ -479,7 +484,7 @@ impl GcObject { let mut set = None; let set_key = PropertyKey::from("set"); - if self.has_property(&set_key) { + if self.has_property(&set_key, context)? { let setter = self.get(&set_key, self.clone().into(), context)?; match setter { Value::Object(ref object) if object.is_callable() => { @@ -504,7 +509,7 @@ impl GcObject { } } - /// Reeturn `true` if it is a native object and the native type is `T`. + /// Return `true` if it is a native object and the native type is `T`. /// /// # Panics /// @@ -731,7 +736,7 @@ impl GcObject { /// /// [spec]: https://tc39.es/ecma262/#sec-getmethod #[inline] - pub fn get_method(&self, context: &mut Context, key: K) -> Result> + pub fn get_method(&self, context: &Context, key: K) -> Result> where K: Into, { @@ -756,11 +761,7 @@ impl GcObject { /// /// [spec]: https://tc39.es/ecma262/#sec-ordinaryhasinstance #[inline] - pub(crate) fn ordinary_has_instance( - &self, - context: &mut Context, - value: &Value, - ) -> Result { + pub(crate) fn ordinary_has_instance(&self, context: &Context, value: &Value) -> Result { if !self.is_callable() { return Ok(false); } @@ -774,12 +775,12 @@ impl GcObject { .get(&"prototype".into(), self.clone().into(), context)? .as_object() { - let mut object = object.get_prototype_of(); + let mut object = object.get_prototype_of(context)?; while let Some(object_prototype) = object.as_object() { if GcObject::equals(&prototype, &object_prototype) { return Ok(true); } - object = object_prototype.get_prototype_of(); + object = object_prototype.get_prototype_of(context)?; } Ok(false) @@ -798,7 +799,7 @@ impl GcObject { K: Into, { let key = key.into(); - self.get_own_property(&key).is_some() + self.ordinary_get_own_property(&key).is_some() } /// Defines the property or throws a `TypeError` if the operation fails. @@ -812,7 +813,7 @@ impl GcObject { &mut self, key: K, desc: P, - context: &mut Context, + context: &Context, ) -> Result<()> where K: Into, @@ -950,7 +951,7 @@ impl Debug for GcObject { let limiter = RecursionLimiter::new(&self); // Typically, using `!limiter.live` would be good enough here. - // However, the JS object hierarchy involves quite a bit of repitition, and the sheer amount of data makes + // However, the JS object hierarchy involves quite a bit of repetition, and the sheer amount of data makes // understanding the Debug output impossible; limiting the usefulness of it. // // Instead, we check if the object has appeared before in the entire graph. This means that objects will appear diff --git a/boa/src/object/internal_methods.rs b/boa/src/object/internal_methods.rs index 98f4a48cb25..b886ae5ce79 100644 --- a/boa/src/object/internal_methods.rs +++ b/boa/src/object/internal_methods.rs @@ -6,11 +6,12 @@ //! [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots use crate::{ - object::{GcObject, Object}, + object::{GcObject, Object, ObjectData}, property::{AccessorDescriptor, Attribute, DataDescriptor, PropertyDescriptor, PropertyKey}, value::{same_value, Value}, BoaProfiler, Context, Result, }; +use std::char::from_u32; impl GcObject { /// Check if object has property. @@ -20,17 +21,27 @@ impl GcObject { /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-hasproperty-p #[inline] - pub fn has_property(&self, key: &PropertyKey) -> bool { - let prop = self.get_own_property(key); + pub fn has_property(&self, key: &PropertyKey, context: &Context) -> Result { + self.ordinary_has_property(key, context) + } + + /// Check if an ordinary object has a property. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinaryhasproperty + pub fn ordinary_has_property(&self, key: &PropertyKey, context: &Context) -> Result { + let prop = self.get_own_property(key, context)?; if prop.is_none() { - let parent = self.get_prototype_of(); + let parent = self.get_prototype_of(context)?; return if let Value::Object(ref object) = parent { - object.has_property(key) + object.has_property(key, context) } else { - false + Ok(false) }; } - true + Ok(true) } /// Check if it is extensible. @@ -40,8 +51,19 @@ impl GcObject { /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-isextensible #[inline] - pub fn is_extensible(&self) -> bool { - self.borrow().extensible + pub fn is_extensible(&self, context: &Context) -> Result { + self.ordinary_is_extensible(context) + } + + /// Check if an ordinary object is extensible. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-isextensible + #[inline] + pub fn ordinary_is_extensible(&self, _context: &Context) -> Result { + Ok(self.borrow().extensible) } /// Disable extensibility. @@ -51,31 +73,67 @@ impl GcObject { /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-preventextensions #[inline] - pub fn prevent_extensions(&mut self) -> bool { + pub fn prevent_extensions(&mut self, context: &Context) -> Result { + self.ordinary_prevent_extensions(context) + } + + /// Disable extensibility for ordinary object. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinarypreventextensions + #[inline] + pub fn ordinary_prevent_extensions(&mut self, _context: &Context) -> Result { self.borrow_mut().extensible = false; - true + Ok(true) + } + /// Delete a property. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-delete-p + pub fn delete(&mut self, key: &PropertyKey, context: &Context) -> Result { + self.ordinary_delete(key, context) } - /// Delete property. + /// Delete a property in an ordinary object + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinarydelete #[inline] - pub fn delete(&mut self, key: &PropertyKey) -> bool { - match self.get_own_property(key) { + pub fn ordinary_delete(&mut self, key: &PropertyKey, context: &Context) -> Result { + match self.get_own_property(key, context)? { Some(desc) if desc.configurable() => { self.remove(&key); - true + Ok(true) } - Some(_) => false, - None => true, + Some(_) => Ok(false), + None => Ok(true), } } /// `[[Get]]` /// - pub fn get(&self, key: &PropertyKey, receiver: Value, context: &mut Context) -> Result { - match self.get_own_property(key) { + pub fn get(&self, key: &PropertyKey, receiver: Value, context: &Context) -> Result { + self.ordinary_get(key, receiver, context) + } + + /// `[[Get]]` for ordinary object + /// + pub fn ordinary_get( + &self, + key: &PropertyKey, + receiver: Value, + context: &Context, + ) -> Result { + match self.get_own_property(key, context)? { None => { // parent will either be null or an Object - if let Some(parent) = self.get_prototype_of().as_object() { + if let Some(parent) = self.get_prototype_of(context)?.as_object() { Ok(parent.get(key, receiver, context)?) } else { Ok(Value::undefined()) @@ -98,14 +156,26 @@ impl GcObject { key: PropertyKey, val: Value, receiver: Value, - context: &mut Context, + context: &Context, + ) -> Result { + self.ordinary_set(key, val, receiver, context) + } + + /// `[[Set]]` for ordinary object + /// + pub fn ordinary_set( + &mut self, + key: PropertyKey, + val: Value, + receiver: Value, + context: &Context, ) -> Result { let _timer = BoaProfiler::global().start_event("Object::set", "object"); // Fetch property key - let own_desc = if let Some(desc) = self.get_own_property(&key) { + let own_desc = if let Some(desc) = self.get_own_property(&key, context)? { desc - } else if let Some(ref mut parent) = self.get_prototype_of().as_object() { + } else if let Some(ref mut parent) = self.get_prototype_of(context)?.as_object() { return Ok(parent.set(key, val, receiver, context)?); } else { DataDescriptor::new(Value::undefined(), Attribute::all()).into() @@ -117,7 +187,7 @@ impl GcObject { return Ok(false); } if let Some(ref mut receiver) = receiver.as_object() { - if let Some(ref existing_desc) = receiver.get_own_property(&key) { + if let Some(ref existing_desc) = receiver.get_own_property(&key, context)? { match existing_desc { PropertyDescriptor::Accessor(_) => Ok(false), PropertyDescriptor::Data(existing_data_desc) => { @@ -161,15 +231,17 @@ impl GcObject { &mut self, key: K, desc: PropertyDescriptor, - context: &mut Context, + context: &Context, ) -> Result where K: Into, { - if self.is_array() { + if self.is_string() { + self.string_define_own_property(key, desc, context) + } else if self.is_array() { self.array_define_own_property(key, desc, context) } else { - Ok(self.ordinary_define_own_property(key, desc)) + self.ordinary_define_own_property(key, desc, context) } } @@ -179,34 +251,39 @@ impl GcObject { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-ordinarydefineownproperty - pub fn ordinary_define_own_property(&mut self, key: K, desc: PropertyDescriptor) -> bool + pub fn ordinary_define_own_property( + &mut self, + key: K, + desc: PropertyDescriptor, + context: &Context, + ) -> Result where K: Into, { let _timer = BoaProfiler::global().start_event("Object::define_own_property", "object"); let key = key.into(); - let extensible = self.is_extensible(); + let extensible = self.is_extensible(context)?; - let current = if let Some(desc) = self.get_own_property(&key) { + let current = if let Some(desc) = self.get_own_property(&key, context)? { desc } else { if !extensible { - return false; + return Ok(false); } self.insert(key, desc); - return true; + return Ok(true); }; // 4 if !current.configurable() { if desc.configurable() { - return false; + return Ok(false); } if desc.enumerable() != current.enumerable() { - return false; + return Ok(false); } } @@ -214,43 +291,43 @@ impl GcObject { (PropertyDescriptor::Data(current), PropertyDescriptor::Data(desc)) => { if !current.configurable() && !current.writable() { if desc.writable() { - return false; + return Ok(false); } if !same_value(&desc.value(), ¤t.value()) { - return false; + return Ok(false); } } } (PropertyDescriptor::Data(current), PropertyDescriptor::Accessor(_)) => { if !current.configurable() { - return false; + return Ok(false); } let current = AccessorDescriptor::new(None, None, current.attributes()); self.insert(key, current); - return true; + return Ok(true); } (PropertyDescriptor::Accessor(current), PropertyDescriptor::Data(_)) => { if !current.configurable() { - return false; + return Ok(false); } let current = DataDescriptor::new(Value::undefined(), current.attributes()); self.insert(key, current); - return true; + return Ok(true); } (PropertyDescriptor::Accessor(current), PropertyDescriptor::Accessor(desc)) => { if !current.configurable() { if let (Some(current_get), Some(desc_get)) = (current.getter(), desc.getter()) { if !GcObject::equals(¤t_get, &desc_get) { - return false; + return Ok(false); } } if let (Some(current_set), Some(desc_set)) = (current.setter(), desc.setter()) { if !GcObject::equals(¤t_set, &desc_set) { - return false; + return Ok(false); } } } @@ -258,7 +335,7 @@ impl GcObject { } self.insert(key, desc); - true + Ok(true) } /// Define an own property for an array. @@ -271,7 +348,7 @@ impl GcObject { &mut self, key: K, desc: PropertyDescriptor, - context: &mut Context, + context: &Context, ) -> Result where K: Into, @@ -281,11 +358,11 @@ impl GcObject { PropertyKey::String(ref s) if s == "length" => { match desc { PropertyDescriptor::Accessor(_) => { - return Ok(self.ordinary_define_own_property("length", desc)) + return self.ordinary_define_own_property("length", desc, context) } PropertyDescriptor::Data(ref d) => { if d.value().is_undefined() { - return Ok(self.ordinary_define_own_property("length", desc)); + return self.ordinary_define_own_property("length", desc, context); } let new_len = d.value().to_u32(context)?; let number_len = d.value().to_number(context)?; @@ -295,11 +372,16 @@ impl GcObject { } let mut new_len_desc = PropertyDescriptor::Data(DataDescriptor::new(new_len, d.attributes())); - let old_len_desc = self.get_own_property(&"length".into()).unwrap(); + let old_len_desc = + self.get_own_property(&"length".into(), context)?.unwrap(); let old_len_desc = old_len_desc.as_data_descriptor().unwrap(); let old_len = old_len_desc.value(); if new_len >= old_len.to_u32(context)? { - return Ok(self.ordinary_define_own_property("length", new_len_desc)); + return self.ordinary_define_own_property( + "length", + new_len_desc, + context, + ); } if !old_len_desc.writable() { return Ok(false); @@ -315,7 +397,11 @@ impl GcObject { )); false }; - if !self.ordinary_define_own_property("length", new_len_desc.clone()) { + if !self.ordinary_define_own_property( + "length", + new_len_desc.clone(), + context, + )? { return Ok(false); } let keys_to_delete = { @@ -329,7 +415,7 @@ impl GcObject { keys }; for key in keys_to_delete.into_iter().rev() { - if !self.delete(&key.into()) { + if !self.delete(&key.into(), context)? { let mut new_len_desc_attribute = new_len_desc.attributes(); if !new_writable { new_len_desc_attribute.set_writable(false); @@ -338,7 +424,7 @@ impl GcObject { key + 1, new_len_desc_attribute, )); - self.ordinary_define_own_property("length", new_len_desc); + self.ordinary_define_own_property("length", new_len_desc, context)?; return Ok(false); } } @@ -349,33 +435,81 @@ impl GcObject { new_len, new_desc_attr, )); - self.ordinary_define_own_property("length", new_desc); + self.ordinary_define_own_property("length", new_desc, context)?; } } } Ok(true) } PropertyKey::Index(index) => { - let old_len_desc = self.get_own_property(&"length".into()).unwrap(); + let old_len_desc = self.get_own_property(&"length".into(), context)?.unwrap(); let old_len_data_desc = old_len_desc.as_data_descriptor().unwrap(); let old_len = old_len_data_desc.value().to_u32(context)?; if index >= old_len && !old_len_data_desc.writable() { return Ok(false); } - if self.ordinary_define_own_property(key, desc) { + if self.ordinary_define_own_property(key, desc, context)? { if index >= old_len && index < std::u32::MAX { let desc = PropertyDescriptor::Data(DataDescriptor::new( index + 1, old_len_data_desc.attributes(), )); - self.ordinary_define_own_property("length", desc); + self.ordinary_define_own_property("length", desc, context)?; } Ok(true) } else { Ok(false) } } - _ => Ok(self.ordinary_define_own_property(key, desc)), + _ => self.ordinary_define_own_property(key, desc, context), + } + } + + /// Define an own property for a string object. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-string-exotic-objects-defineownproperty-p-desc + pub fn string_define_own_property( + &mut self, + key: K, + desc: PropertyDescriptor, + context: &Context, + ) -> Result + where + K: Into, + { + let key = key.into(); + if let Some(d) = self.string_get_own_property(&key) { + // This is a simplified version of the spec, need to implement IsCompatiblePropertyDescriptor + // to make it really compliant + if self.is_extensible(context)? && d.attributes().writable() { + self.ordinary_define_own_property(key, desc, context) + } else { + Ok(false) + } + } else { + self.ordinary_define_own_property(key, desc, context) + } + } + + /// The specification returns a Property Descriptor or Undefined. + /// + /// These are 2 separate types and we can't do that here. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-getownproperty-p + pub fn get_own_property( + &self, + key: &PropertyKey, + _context: &Context, + ) -> Result> { + match &self.borrow().data { + ObjectData::String(_) => Ok(self.string_get_own_property(key)), + _ => Ok(self.ordinary_get_own_property(key)), } } @@ -388,7 +522,7 @@ impl GcObject { /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-getownproperty-p #[inline] - pub fn get_own_property(&self, key: &PropertyKey) -> Option { + pub fn ordinary_get_own_property(&self, key: &PropertyKey) -> Option { let _timer = BoaProfiler::global().start_event("Object::get_own_property", "object"); let object = self.borrow(); @@ -401,18 +535,86 @@ impl GcObject { property.cloned() } + /// `[[GetOwnProperty]]` for string object + /// + /// [spec]: https://tc39.es/ecma262/#sec-stringgetownproperty + pub fn string_get_own_property(&self, key: &PropertyKey) -> Option { + match key { + PropertyKey::Index(index) => { + let string = self.borrow().as_string().unwrap(); + if let Some(utf16_val) = string.encode_utf16().nth(*index as usize) { + if let Some(c) = from_u32(utf16_val as u32) { + Some( + DataDescriptor::new( + Value::from(c), + Attribute::READONLY | Attribute::ENUMERABLE | Attribute::PERMANENT, + ) + .into(), + ) + } else { + None + } + } else { + self.ordinary_get_own_property(key) + } + } + _ => self.ordinary_get_own_property(key), + } + } + /// Essential internal method OwnPropertyKeys /// /// More information: /// - [ECMAScript reference][spec] /// - /// [spec]: https://tc39.es/ecma262/#table-essential-internal-methods + /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys #[inline] #[track_caller] - pub fn own_property_keys(&self) -> Vec { + pub fn own_property_keys(&self, _context: &Context) -> Result> { + if self.is_string() { + Ok(self.string_own_property_keys()) + } else { + Ok(self.ordinary_own_property_keys()) + } + } + + /// OwnPropertyKeys for ordinary objects + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinaryownpropertykeys + pub fn ordinary_own_property_keys(&self) -> Vec { self.borrow().keys().collect() } + /// OwnPropertyKeys for ordinary objects + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinaryownpropertykeys + pub fn string_own_property_keys(&self) -> Vec { + let string = self.borrow().as_string().unwrap(); + let mut property_keys = Vec::new(); + let len = string.encode_utf16().count(); + for i in 0..len { + property_keys.push(PropertyKey::from(i)); + } + for i in self.borrow().index_property_keys() { + if *i >= len as u32 { + property_keys.push(PropertyKey::from(*i)); + } + } + for s in self.borrow().symbol_property_keys() { + property_keys.push(PropertyKey::from(s.clone())); + } + for s in self.borrow().string_property_keys() { + property_keys.push(PropertyKey::from(s.clone())); + } + property_keys + } + /// The abstract operation ObjectDefineProperties /// /// More information: @@ -420,13 +622,13 @@ impl GcObject { /// /// [spec]: https://tc39.es/ecma262/#sec-object.defineproperties #[inline] - pub fn define_properties(&mut self, props: Value, context: &mut Context) -> Result<()> { + pub fn define_properties(&mut self, props: Value, context: &Context) -> Result<()> { let props = &props.to_object(context)?; - let keys = props.own_property_keys(); + let keys = props.own_property_keys(context)?; let mut descriptors: Vec<(PropertyKey, PropertyDescriptor)> = Vec::new(); for next_key in keys { - if let Some(prop_desc) = props.get_own_property(&next_key) { + if let Some(prop_desc) = props.get_own_property(&next_key, context)? { if prop_desc.enumerable() { let desc_obj = props.get(&next_key, props.clone().into(), context)?; let desc = desc_obj.to_property_descriptor(context)?; @@ -442,6 +644,16 @@ impl GcObject { Ok(()) } + /// Internal slot for `[[SetPropertypeOf]]` + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-setprototypeof-v + pub fn set_prototype_of(&mut self, val: Value, context: &Context) -> Result { + self.ordinary_set_prototype_of(val, context) + } + /// `Object.setPropertyOf(obj, prototype)` /// /// This method sets the prototype (i.e., the internal `[[Prototype]]` property) @@ -454,14 +666,14 @@ impl GcObject { /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-setprototypeof-v /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf #[inline] - pub fn set_prototype_of(&mut self, val: Value) -> bool { + pub fn ordinary_set_prototype_of(&mut self, val: Value, context: &Context) -> Result { debug_assert!(val.is_object() || val.is_null()); - let current = self.get_prototype_of(); + let current = self.get_prototype_of(context)?; if same_value(¤t, &val) { - return true; + return Ok(true); } - if !self.is_extensible() { - return false; + if !self.is_extensible(context)? { + return Ok(false); } let mut p = val.clone(); let mut done = false; @@ -469,17 +681,17 @@ impl GcObject { if p.is_null() { done = true } else if same_value(&Value::from(self.clone()), &p) { - return false; + return Ok(false); } else { let prototype = p .as_object() .expect("prototype should be null or object") - .get_prototype_of(); + .get_prototype_of(context)?; p = prototype; } } self.set_prototype_instance(val); - true + Ok(true) } /// Returns either the prototype or null @@ -492,7 +704,19 @@ impl GcObject { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf #[inline] #[track_caller] - pub fn get_prototype_of(&self) -> Value { + pub fn get_prototype_of(&self, _context: &Context) -> Result { + Ok(self.ordinary_get_prototype_of()) + } + + /// Returns either the prototype or null + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-ordinarygetprototypeof + #[inline] + #[track_caller] + pub fn ordinary_get_prototype_of(&self) -> Value { self.borrow().prototype.clone() } diff --git a/boa/src/object/mod.rs b/boa/src/object/mod.rs index 93874f107a8..2c296333db1 100644 --- a/boa/src/object/mod.rs +++ b/boa/src/object/mod.rs @@ -636,7 +636,7 @@ where /// Builder for creating native function objects #[derive(Debug)] pub struct FunctionBuilder<'context> { - context: &'context mut Context, + context: &'context Context, function: BuiltInFunction, name: Option, length: usize, @@ -647,7 +647,7 @@ pub struct FunctionBuilder<'context> { impl<'context> FunctionBuilder<'context> { /// Create a new `FunctionBuilder` #[inline] - pub fn new(context: &'context mut Context, function: NativeFunction) -> Self { + pub fn new(context: &'context Context, function: NativeFunction) -> Self { Self { context, function: function.into(), @@ -772,14 +772,14 @@ impl<'context> FunctionBuilder<'context> { /// ``` #[derive(Debug)] pub struct ObjectInitializer<'context> { - context: &'context mut Context, + context: &'context Context, object: GcObject, } impl<'context> ObjectInitializer<'context> { /// Create a new `ObjectBuilder`. #[inline] - pub fn new(context: &'context mut Context) -> Self { + pub fn new(context: &'context Context) -> Self { let object = context.construct_object(); Self { context, object } } @@ -827,7 +827,7 @@ impl<'context> ObjectInitializer<'context> { /// Builder for creating constructors objects, like `Array`. pub struct ConstructorBuilder<'context> { - context: &'context mut Context, + context: &'context Context, constructor_function: NativeFunction, constructor_object: GcObject, prototype: GcObject, @@ -855,7 +855,7 @@ impl Debug for ConstructorBuilder<'_> { impl<'context> ConstructorBuilder<'context> { /// Create a new `ConstructorBuilder`. #[inline] - pub fn new(context: &'context mut Context, constructor: NativeFunction) -> Self { + pub fn new(context: &'context Context, constructor: NativeFunction) -> Self { Self { context, constructor_function: constructor, @@ -871,7 +871,7 @@ impl<'context> ConstructorBuilder<'context> { #[inline] pub(crate) fn with_standard_object( - context: &'context mut Context, + context: &'context Context, constructor: NativeFunction, object: StandardConstructor, ) -> Self { @@ -1012,7 +1012,7 @@ impl<'context> ConstructorBuilder<'context> { /// Return the current context. #[inline] - pub fn context(&mut self) -> &'_ mut Context { + pub fn context(&mut self) -> &'_ Context { self.context } diff --git a/boa/src/realm.rs b/boa/src/realm.rs index cfa23c38277..ea4bd786bf6 100644 --- a/boa/src/realm.rs +++ b/boa/src/realm.rs @@ -16,6 +16,7 @@ use crate::{ }; use gc::{Gc, GcCell}; use rustc_hash::{FxHashMap, FxHashSet}; +use std::cell::RefCell; /// Representation of a Realm. /// @@ -24,7 +25,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; pub struct Realm { pub global_object: Value, pub global_env: Gc>, - pub environment: LexicalEnvironment, + pub environment: RefCell, } impl Realm { @@ -43,7 +44,7 @@ impl Realm { Self { global_object: global.clone(), global_env, - environment: LexicalEnvironment::new(global), + environment: RefCell::new(LexicalEnvironment::new(global)), } } } diff --git a/boa/src/syntax/ast/node/array/mod.rs b/boa/src/syntax/ast/node/array/mod.rs index 7096770918b..f0a1962ebcf 100644 --- a/boa/src/syntax/ast/node/array/mod.rs +++ b/boa/src/syntax/ast/node/array/mod.rs @@ -36,7 +36,7 @@ pub struct ArrayDecl { } impl Executable for ArrayDecl { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("ArrayDecl", "exec"); let array = Array::new_array(context)?; let mut elements = Vec::new(); diff --git a/boa/src/syntax/ast/node/await_expr/mod.rs b/boa/src/syntax/ast/node/await_expr/mod.rs index f527dd0f067..b97324f85de 100644 --- a/boa/src/syntax/ast/node/await_expr/mod.rs +++ b/boa/src/syntax/ast/node/await_expr/mod.rs @@ -24,7 +24,7 @@ pub struct AwaitExpr { } impl Executable for AwaitExpr { - fn run(&self, _: &mut Context) -> Result { + fn run(&self, _: &Context) -> Result { let _timer = BoaProfiler::global().start_event("AwaitExpression", "exec"); // TODO: Implement AwaitExpr Ok(Value::Undefined) diff --git a/boa/src/syntax/ast/node/block/mod.rs b/boa/src/syntax/ast/node/block/mod.rs index 93bedf48161..332af8bae29 100644 --- a/boa/src/syntax/ast/node/block/mod.rs +++ b/boa/src/syntax/ast/node/block/mod.rs @@ -51,13 +51,12 @@ impl Block { } impl Executable for Block { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("Block", "exec"); { - let env = &mut context.realm_mut().environment; - env.push(new_declarative_environment(Some( - env.get_current_environment_ref().clone(), - ))); + let env = &mut context.realm().environment.borrow(); + let current_env = env.get_current_environment(); + env.push(new_declarative_environment(Some(current_env))); } // https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation @@ -66,7 +65,7 @@ impl Executable for Block { for statement in self.items() { obj = statement.run(context)?; - match context.executor().get_current_state() { + match context.executor().borrow().get_current_state() { InterpreterState::Return => { // Early return. break; @@ -88,7 +87,7 @@ impl Executable for Block { } // pop the block env - let _ = context.realm_mut().environment.pop(); + let _ = context.realm().environment.borrow().pop(); Ok(obj) } diff --git a/boa/src/syntax/ast/node/break_node/mod.rs b/boa/src/syntax/ast/node/break_node/mod.rs index 48b6108f78e..bc52b05856c 100644 --- a/boa/src/syntax/ast/node/break_node/mod.rs +++ b/boa/src/syntax/ast/node/break_node/mod.rs @@ -52,9 +52,10 @@ impl Break { } impl Executable for Break { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { context .executor() + .borrow_mut() .set_current_state(InterpreterState::Break(self.label().map(Box::from))); Ok(Value::undefined()) diff --git a/boa/src/syntax/ast/node/break_node/tests.rs b/boa/src/syntax/ast/node/break_node/tests.rs index 194c22c2b8a..cfa7b24baa2 100644 --- a/boa/src/syntax/ast/node/break_node/tests.rs +++ b/boa/src/syntax/ast/node/break_node/tests.rs @@ -13,7 +13,7 @@ fn check_post_state() { brk.run(&mut context).unwrap(); assert_eq!( - context.executor().get_current_state(), + context.executor().borrow().get_current_state(), &InterpreterState::Break(Some("label".into())) ); } diff --git a/boa/src/syntax/ast/node/call/mod.rs b/boa/src/syntax/ast/node/call/mod.rs index f742042339d..6d3916e73a4 100644 --- a/boa/src/syntax/ast/node/call/mod.rs +++ b/boa/src/syntax/ast/node/call/mod.rs @@ -58,7 +58,7 @@ impl Call { } impl Executable for Call { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("Call", "exec"); let (this, func) = match self.expr() { Node::GetConstField(ref get_const_field) => { @@ -106,6 +106,7 @@ impl Executable for Call { // unset the early return flag context .executor() + .borrow_mut() .set_current_state(InterpreterState::Executing); fnct_result diff --git a/boa/src/syntax/ast/node/conditional/conditional_op/mod.rs b/boa/src/syntax/ast/node/conditional/conditional_op/mod.rs index f6c07f14e78..e0d1327667c 100644 --- a/boa/src/syntax/ast/node/conditional/conditional_op/mod.rs +++ b/boa/src/syntax/ast/node/conditional/conditional_op/mod.rs @@ -60,7 +60,7 @@ impl ConditionalOp { } impl Executable for ConditionalOp { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { Ok(if self.cond().run(context)?.to_boolean() { self.if_true().run(context)? } else { diff --git a/boa/src/syntax/ast/node/conditional/if_node/mod.rs b/boa/src/syntax/ast/node/conditional/if_node/mod.rs index 63906833a80..4f703ccafec 100644 --- a/boa/src/syntax/ast/node/conditional/if_node/mod.rs +++ b/boa/src/syntax/ast/node/conditional/if_node/mod.rs @@ -79,7 +79,7 @@ impl If { } impl Executable for If { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { Ok(if self.cond().run(context)?.to_boolean() { self.body().run(context)? } else if let Some(ref else_e) = self.else_node() { diff --git a/boa/src/syntax/ast/node/declaration/arrow_function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/arrow_function_decl/mod.rs index f1306209d20..858489a54d2 100644 --- a/boa/src/syntax/ast/node/declaration/arrow_function_decl/mod.rs +++ b/boa/src/syntax/ast/node/declaration/arrow_function_decl/mod.rs @@ -67,7 +67,7 @@ impl ArrowFunctionDecl { } impl Executable for ArrowFunctionDecl { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { Ok(context.create_function( self.params().to_vec(), self.body().to_vec(), diff --git a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs index 5078b5b2940..bc2a599f612 100644 --- a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs +++ b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs @@ -81,7 +81,7 @@ impl AsyncFunctionDecl { } impl Executable for AsyncFunctionDecl { - fn run(&self, _: &mut Context) -> Result { + fn run(&self, _: &Context) -> Result { let _timer = BoaProfiler::global().start_event("AsyncFunctionDecl", "exec"); // TODO: Implement AsyncFunctionDecl Ok(Value::undefined()) diff --git a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs index 056976f9619..a0de0e54a96 100644 --- a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs +++ b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs @@ -79,7 +79,7 @@ impl AsyncFunctionExpr { } impl Executable for AsyncFunctionExpr { - fn run(&self, _: &mut Context) -> Result { + fn run(&self, _: &Context) -> Result { // TODO: Implement AsyncFunctionExpr Ok(Value::Undefined) } diff --git a/boa/src/syntax/ast/node/declaration/const_decl_list/mod.rs b/boa/src/syntax/ast/node/declaration/const_decl_list/mod.rs index 9c392854ce6..abf39a0090e 100644 --- a/boa/src/syntax/ast/node/declaration/const_decl_list/mod.rs +++ b/boa/src/syntax/ast/node/declaration/const_decl_list/mod.rs @@ -36,7 +36,7 @@ pub struct ConstDeclList { } impl Executable for ConstDeclList { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { for decl in self.as_ref() { let val = if let Some(init) = decl.init() { init.run(context)? @@ -44,16 +44,21 @@ impl Executable for ConstDeclList { return context.throw_syntax_error("missing = in const declaration"); }; context - .realm_mut() + .realm() .environment - .create_immutable_binding(decl.name().to_owned(), false, VariableScope::Block) - .map_err(|e| e.to_error(context))?; + .borrow() + .create_immutable_binding( + decl.name().to_owned(), + false, + VariableScope::Block, + context, + )?; context - .realm_mut() + .realm() .environment - .initialize_binding(decl.name(), val) - .map_err(|e| e.to_error(context))?; + .borrow() + .initialize_binding(decl.name(), val, context)?; } Ok(Value::undefined()) } diff --git a/boa/src/syntax/ast/node/declaration/function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/function_decl/mod.rs index 999faebdd42..42aefc42b78 100644 --- a/boa/src/syntax/ast/node/declaration/function_decl/mod.rs +++ b/boa/src/syntax/ast/node/declaration/function_decl/mod.rs @@ -84,7 +84,7 @@ impl FunctionDecl { } impl Executable for FunctionDecl { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("FunctionDecl", "exec"); let val = context.create_function( self.parameters().to_vec(), @@ -95,21 +95,17 @@ impl Executable for FunctionDecl { // Set the name and assign it in the current environment val.set_field("name", self.name(), context)?; - let environment = &mut context.realm_mut().environment; - if environment.has_binding(self.name()) { - environment - .set_mutable_binding(self.name(), val, true) - .map_err(|e| e.to_error(context))?; + let environment = &mut context.realm().environment.borrow(); + if environment.has_binding(self.name(), context)? { + environment.set_mutable_binding(self.name(), val, true, context)?; } else { - environment - .create_mutable_binding(self.name().to_owned(), false, VariableScope::Function) - .map_err(|e| e.to_error(context))?; - - context - .realm_mut() - .environment - .initialize_binding(self.name(), val) - .map_err(|e| e.to_error(context))?; + environment.create_mutable_binding( + self.name().to_owned(), + false, + VariableScope::Function, + context, + )?; + environment.initialize_binding(self.name(), val, context)?; } Ok(Value::undefined()) } diff --git a/boa/src/syntax/ast/node/declaration/function_expr/mod.rs b/boa/src/syntax/ast/node/declaration/function_expr/mod.rs index 6f56d54cf6c..fe28cc52971 100644 --- a/boa/src/syntax/ast/node/declaration/function_expr/mod.rs +++ b/boa/src/syntax/ast/node/declaration/function_expr/mod.rs @@ -85,7 +85,7 @@ impl FunctionExpr { } impl Executable for FunctionExpr { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let val = context.create_function( self.parameters().to_vec(), self.body().to_vec(), diff --git a/boa/src/syntax/ast/node/declaration/let_decl_list/mod.rs b/boa/src/syntax/ast/node/declaration/let_decl_list/mod.rs index 2596df660c3..cc5c2c95c93 100644 --- a/boa/src/syntax/ast/node/declaration/let_decl_list/mod.rs +++ b/boa/src/syntax/ast/node/declaration/let_decl_list/mod.rs @@ -35,22 +35,27 @@ pub struct LetDeclList { } impl Executable for LetDeclList { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { for var in self.as_ref() { let val = match var.init() { Some(v) => v.run(context)?, None => Value::undefined(), }; context - .realm_mut() + .realm() .environment - .create_mutable_binding(var.name().to_owned(), false, VariableScope::Block) - .map_err(|e| e.to_error(context))?; + .borrow() + .create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + context, + )?; context - .realm_mut() + .realm() .environment - .initialize_binding(var.name(), val) - .map_err(|e| e.to_error(context))?; + .borrow() + .initialize_binding(var.name(), val, context)?; } Ok(Value::undefined()) } diff --git a/boa/src/syntax/ast/node/declaration/var_decl_list/mod.rs b/boa/src/syntax/ast/node/declaration/var_decl_list/mod.rs index 061a94c4cd7..4f77126b587 100644 --- a/boa/src/syntax/ast/node/declaration/var_decl_list/mod.rs +++ b/boa/src/syntax/ast/node/declaration/var_decl_list/mod.rs @@ -36,28 +36,26 @@ pub struct VarDeclList { } impl Executable for VarDeclList { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { for var in self.as_ref() { let val = match var.init() { Some(v) => v.run(context)?, None => Value::undefined(), }; - let environment = &mut context.realm_mut().environment; + let environment = &mut context.realm().environment.borrow(); - if environment.has_binding(var.name()) { + if environment.has_binding(var.name(), context)? { if var.init().is_some() { - environment - .set_mutable_binding(var.name(), val, true) - .map_err(|e| e.to_error(context))?; + environment.set_mutable_binding(var.name(), val, true, context)?; } } else { - environment - .create_mutable_binding(var.name().to_owned(), false, VariableScope::Function) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), val) - .map_err(|e| e.to_error(context))?; + environment.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Function, + context, + )?; + environment.initialize_binding(var.name(), val, context)?; } } Ok(Value::undefined()) diff --git a/boa/src/syntax/ast/node/field/get_const_field/mod.rs b/boa/src/syntax/ast/node/field/get_const_field/mod.rs index 80287d076e5..1c1b591ed40 100644 --- a/boa/src/syntax/ast/node/field/get_const_field/mod.rs +++ b/boa/src/syntax/ast/node/field/get_const_field/mod.rs @@ -63,7 +63,7 @@ impl GetConstField { } impl Executable for GetConstField { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let mut obj = self.obj().run(context)?; if obj.get_type() != Type::Object { obj = Value::Object(obj.to_object(context)?); diff --git a/boa/src/syntax/ast/node/field/get_field/mod.rs b/boa/src/syntax/ast/node/field/get_field/mod.rs index e85ac02333a..011ea822b54 100644 --- a/boa/src/syntax/ast/node/field/get_field/mod.rs +++ b/boa/src/syntax/ast/node/field/get_field/mod.rs @@ -62,7 +62,7 @@ impl GetField { } impl Executable for GetField { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let mut obj = self.obj().run(context)?; if obj.get_type() != Type::Object { obj = Value::Object(obj.to_object(context)?); diff --git a/boa/src/syntax/ast/node/identifier/mod.rs b/boa/src/syntax/ast/node/identifier/mod.rs index 25f46b66474..b8fc28d3e31 100644 --- a/boa/src/syntax/ast/node/identifier/mod.rs +++ b/boa/src/syntax/ast/node/identifier/mod.rs @@ -35,12 +35,12 @@ pub struct Identifier { } impl Executable for Identifier { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { context .realm() .environment - .get_binding_value(self.as_ref()) - .map_err(|e| e.to_error(context)) + .borrow() + .get_binding_value(self.as_ref(), context) } } diff --git a/boa/src/syntax/ast/node/iteration/continue_node/mod.rs b/boa/src/syntax/ast/node/iteration/continue_node/mod.rs index f42864339dd..0bfbef2b951 100644 --- a/boa/src/syntax/ast/node/iteration/continue_node/mod.rs +++ b/boa/src/syntax/ast/node/iteration/continue_node/mod.rs @@ -46,9 +46,10 @@ impl Continue { } impl Executable for Continue { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { context .executor() + .borrow_mut() .set_current_state(InterpreterState::Continue(self.label().map(Box::from))); Ok(Value::undefined()) diff --git a/boa/src/syntax/ast/node/iteration/do_while_loop/mod.rs b/boa/src/syntax/ast/node/iteration/do_while_loop/mod.rs index 19a828d6588..672bf011c0a 100644 --- a/boa/src/syntax/ast/node/iteration/do_while_loop/mod.rs +++ b/boa/src/syntax/ast/node/iteration/do_while_loop/mod.rs @@ -71,17 +71,18 @@ impl DoWhileLoop { } impl Executable for DoWhileLoop { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let mut result; loop { result = self.body().run(context)?; - match context.executor().get_current_state() { + let executor = &mut context.executor().borrow_mut(); + match executor.get_current_state() { InterpreterState::Break(label) => { - handle_state_with_labels!(self, label, context, break); + handle_state_with_labels!(self, label, executor, break); break; } InterpreterState::Continue(label) => { - handle_state_with_labels!(self, label, context, continue); + handle_state_with_labels!(self, label, executor, continue); } InterpreterState::Return => { return Ok(result); diff --git a/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs b/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs index 9841aedb3c7..b36fd5bde29 100644 --- a/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs +++ b/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs @@ -75,7 +75,7 @@ impl From for Node { } impl Executable for ForInLoop { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("ForIn", "exec"); let object = self.expr().run(context)?; let mut result = Value::undefined(); @@ -86,17 +86,16 @@ impl Executable for ForInLoop { let object = object.to_object(context)?; let for_in_iterator = ForInIterator::create_for_in_iterator(context, Value::from(object))?; let next_function = for_in_iterator - .get_property("next") + .get_property("next", context)? .map(|p| p.as_data_descriptor().unwrap().value()) .ok_or_else(|| context.construct_type_error("Could not find property `next`"))?; let iterator = IteratorRecord::new(for_in_iterator, next_function); loop { { - let env = &mut context.realm_mut().environment; - env.push(new_declarative_environment(Some( - env.get_current_environment_ref().clone(), - ))); + let env = &mut context.realm().environment.borrow(); + let current_env = env.get_current_environment(); + env.push(new_declarative_environment(Some(current_env))); } let iterator_result = iterator.next(context)?; if iterator_result.is_done() { @@ -106,51 +105,53 @@ impl Executable for ForInLoop { match self.variable() { Node::Identifier(ref name) => { - let environment = &mut context.realm_mut().environment; + let environment = &mut context.realm().environment.borrow(); - if environment.has_binding(name.as_ref()) { + if environment.has_binding(name.as_ref(), context)? { // Binding already exists - environment - .set_mutable_binding(name.as_ref(), next_result.clone(), true) - .map_err(|e| e.to_error(context))?; + environment.set_mutable_binding( + name.as_ref(), + next_result.clone(), + true, + context, + )?; } else { - environment - .create_mutable_binding( - name.as_ref().to_owned(), - true, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(name.as_ref(), next_result.clone()) - .map_err(|e| e.to_error(context))?; + environment.create_mutable_binding( + name.as_ref().to_owned(), + true, + VariableScope::Function, + context, + )?; + environment.initialize_binding( + name.as_ref(), + next_result.clone(), + context, + )?; } } Node::VarDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; + let environment = &mut context.realm().environment.borrow(); if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-in loop can't have an initializer"); } - if environment.has_binding(var.name()) { - environment - .set_mutable_binding(var.name(), next_result, true) - .map_err(|e| e.to_error(context))?; + if environment.has_binding(var.name(), context)? { + environment.set_mutable_binding( + var.name(), + next_result, + true, + context, + )? } else { - environment - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + environment.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Function, + context, + )?; + environment.initialize_binding(var.name(), next_result, context)?; } } _ => { @@ -161,23 +162,19 @@ impl Executable for ForInLoop { }, Node::LetDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; + let environment = &mut context.realm().environment.borrow(); if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-in loop can't have an initializer"); } - environment - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + environment.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + context, + )?; + environment.initialize_binding(var.name(), next_result, context)?; } _ => { return context.throw_syntax_error( @@ -187,23 +184,19 @@ impl Executable for ForInLoop { }, Node::ConstDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; + let environment = &mut context.realm().environment.borrow(); if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-in loop can't have an initializer"); } - environment - .create_immutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + environment.create_immutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + context, + )?; + environment.initialize_binding(var.name(), next_result, context)?; } _ => { return context.throw_syntax_error( @@ -223,20 +216,21 @@ impl Executable for ForInLoop { } result = self.body().run(context)?; - match context.executor().get_current_state() { + let executor = &mut context.executor().borrow_mut(); + match executor.get_current_state() { InterpreterState::Break(label) => { - handle_state_with_labels!(self, label, context, break); + handle_state_with_labels!(self, label, executor, break); break; } InterpreterState::Continue(label) => { - handle_state_with_labels!(self, label, context, continue); + handle_state_with_labels!(self, label, executor, continue); } InterpreterState::Return => return Ok(result), InterpreterState::Executing => { // Continue execution. } } - let _ = context.realm_mut().environment.pop(); + let _ = context.realm().environment.borrow().pop(); } Ok(result) } diff --git a/boa/src/syntax/ast/node/iteration/for_loop/mod.rs b/boa/src/syntax/ast/node/iteration/for_loop/mod.rs index 4936c8b072b..b5729ed2cb7 100644 --- a/boa/src/syntax/ast/node/iteration/for_loop/mod.rs +++ b/boa/src/syntax/ast/node/iteration/for_loop/mod.rs @@ -98,14 +98,13 @@ impl ForLoop { } impl Executable for ForLoop { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { // Create the block environment. let _timer = BoaProfiler::global().start_event("ForLoop", "exec"); { - let env = &mut context.realm_mut().environment; - env.push(new_declarative_environment(Some( - env.get_current_environment_ref().clone(), - ))); + let env = &mut context.realm().environment.borrow(); + let current_env = env.get_current_environment(); + env.push(new_declarative_environment(Some(current_env))); } if let Some(init) = self.init() { @@ -119,31 +118,32 @@ impl Executable for ForLoop { .unwrap_or(true) { let result = self.body().run(context)?; - - match context.executor().get_current_state() { - InterpreterState::Break(label) => { - handle_state_with_labels!(self, label, context, break); - break; - } - InterpreterState::Continue(label) => { - handle_state_with_labels!(self, label, context, continue); - } - - InterpreterState::Return => { - return Ok(result); - } - InterpreterState::Executing => { - // Continue execution. + { + let executor = &mut context.executor().borrow_mut(); + match executor.get_current_state() { + InterpreterState::Break(label) => { + handle_state_with_labels!(self, label, executor, break); + break; + } + InterpreterState::Continue(label) => { + handle_state_with_labels!(self, label, executor, continue); + } + + InterpreterState::Return => { + return Ok(result); + } + InterpreterState::Executing => { + // Continue execution. + } } } - if let Some(final_expr) = self.final_expr() { final_expr.run(context)?; } } // pop the block env - let _ = context.realm_mut().environment.pop(); + let _ = context.realm().environment.borrow().pop(); Ok(Value::undefined()) } diff --git a/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs b/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs index f0611c90ea0..a7a230ec65c 100644 --- a/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs +++ b/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs @@ -75,7 +75,7 @@ impl From for Node { } impl Executable for ForOfLoop { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("ForOf", "exec"); let iterable = self.iterable().run(context)?; let iterator = get_iterator(context, iterable)?; @@ -83,10 +83,9 @@ impl Executable for ForOfLoop { loop { { - let env = &mut context.realm_mut().environment; - env.push(new_declarative_environment(Some( - env.get_current_environment_ref().clone(), - ))); + let env = &mut context.realm().environment.borrow(); + let current_env = env.get_current_environment(); + env.push(new_declarative_environment(Some(current_env))); } let iterator_result = iterator.next(context)?; if iterator_result.is_done() { @@ -96,51 +95,53 @@ impl Executable for ForOfLoop { match self.variable() { Node::Identifier(ref name) => { - let environment = &mut context.realm_mut().environment; + let environment = &mut context.realm().environment.borrow(); - if environment.has_binding(name.as_ref()) { + if environment.has_binding(name.as_ref(), context)? { // Binding already exists - environment - .set_mutable_binding(name.as_ref(), next_result.clone(), true) - .map_err(|e| e.to_error(context))?; + environment.set_mutable_binding( + name.as_ref(), + next_result.clone(), + true, + context, + )?; } else { - environment - .create_mutable_binding( - name.as_ref().to_owned(), - true, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(name.as_ref(), next_result.clone()) - .map_err(|e| e.to_error(context))?; + environment.create_mutable_binding( + name.as_ref().to_owned(), + true, + VariableScope::Function, + context, + )?; + environment.initialize_binding( + name.as_ref(), + next_result.clone(), + context, + )?; } } Node::VarDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; + let environment = &mut context.realm().environment.borrow(); if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-of loop can't have an initializer"); } - if environment.has_binding(var.name()) { - environment - .set_mutable_binding(var.name(), next_result, true) - .map_err(|e| e.to_error(context))?; + if environment.has_binding(var.name(), context)? { + environment.set_mutable_binding( + var.name(), + next_result, + true, + context, + )?; } else { - environment - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + environment.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Function, + context, + )?; + environment.initialize_binding(var.name(), next_result, context)?; } } _ => { @@ -151,24 +152,19 @@ impl Executable for ForOfLoop { }, Node::LetDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; + let environment = &mut context.realm().environment.borrow(); if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-of loop can't have an initializer"); } - environment - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + environment.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + context, + )?; + environment.initialize_binding(var.name(), next_result, context)?; } _ => { return context.throw_syntax_error( @@ -178,23 +174,19 @@ impl Executable for ForOfLoop { }, Node::ConstDeclList(ref list) => match list.as_ref() { [var] => { - let environment = &mut context.realm_mut().environment; + let environment = &mut context.realm().environment.borrow(); if var.init().is_some() { return context.throw_syntax_error("a declaration in the head of a for-of loop can't have an initializer"); } - environment - .create_immutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + environment.create_immutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + context, + )?; + environment.initialize_binding(var.name(), next_result, context)?; } _ => { return context.throw_syntax_error( @@ -214,20 +206,21 @@ impl Executable for ForOfLoop { } result = self.body().run(context)?; - match context.executor().get_current_state() { + let executor = &mut context.executor().borrow_mut(); + match executor.get_current_state() { InterpreterState::Break(label) => { - handle_state_with_labels!(self, label, context, break); + handle_state_with_labels!(self, label, executor, break); break; } InterpreterState::Continue(label) => { - handle_state_with_labels!(self, label, context, continue); + handle_state_with_labels!(self, label, executor, continue); } InterpreterState::Return => return Ok(result), InterpreterState::Executing => { // Continue execution. } } - let _ = context.realm_mut().environment.pop(); + let _ = context.realm().environment.borrow().pop(); } Ok(result) } diff --git a/boa/src/syntax/ast/node/iteration/mod.rs b/boa/src/syntax/ast/node/iteration/mod.rs index 362e2cb4d01..4a9741c2f17 100644 --- a/boa/src/syntax/ast/node/iteration/mod.rs +++ b/boa/src/syntax/ast/node/iteration/mod.rs @@ -24,9 +24,7 @@ macro_rules! handle_state_with_labels { } } - $interpreter - .executor() - .set_current_state(InterpreterState::Executing); + $interpreter.set_current_state(InterpreterState::Executing); }}; } diff --git a/boa/src/syntax/ast/node/iteration/while_loop/mod.rs b/boa/src/syntax/ast/node/iteration/while_loop/mod.rs index bc4c3d23bde..1bbc70c85d3 100644 --- a/boa/src/syntax/ast/node/iteration/while_loop/mod.rs +++ b/boa/src/syntax/ast/node/iteration/while_loop/mod.rs @@ -69,17 +69,18 @@ impl WhileLoop { } impl Executable for WhileLoop { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let mut result = Value::undefined(); while self.cond().run(context)?.to_boolean() { result = self.expr().run(context)?; - match context.executor().get_current_state() { + let executor = &mut context.executor().borrow_mut(); + match executor.get_current_state() { InterpreterState::Break(label) => { - handle_state_with_labels!(self, label, context, break); + handle_state_with_labels!(self, label, executor, break); break; } InterpreterState::Continue(label) => { - handle_state_with_labels!(self, label, context, continue) + handle_state_with_labels!(self, label, executor, continue) } InterpreterState::Return => { return Ok(result); diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 06119dc9fd0..6b0f797463c 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -279,7 +279,7 @@ impl Node { } impl Executable for Node { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("Executable", "exec"); match *self { Node::AsyncFunctionDecl(ref decl) => decl.run(context), @@ -332,8 +332,8 @@ impl Executable for Node { context .realm() .environment - .get_this_binding() - .map_err(|e| e.to_error(context)) + .borrow() + .get_this_binding(context) } Node::Try(ref try_node) => try_node.run(context), Node::Break(ref break_node) => break_node.run(context), diff --git a/boa/src/syntax/ast/node/new/mod.rs b/boa/src/syntax/ast/node/new/mod.rs index 85be684e413..b929c235349 100644 --- a/boa/src/syntax/ast/node/new/mod.rs +++ b/boa/src/syntax/ast/node/new/mod.rs @@ -45,7 +45,7 @@ impl New { } impl Executable for New { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("New", "exec"); let func_object = self.expr().run(context)?; diff --git a/boa/src/syntax/ast/node/object/mod.rs b/boa/src/syntax/ast/node/object/mod.rs index 4919c937755..d5ec63d1b2d 100644 --- a/boa/src/syntax/ast/node/object/mod.rs +++ b/boa/src/syntax/ast/node/object/mod.rs @@ -72,7 +72,7 @@ impl Object { } impl Executable for Object { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let obj = Value::new_object(context); // TODO: Implement the rest of the property types. @@ -99,7 +99,7 @@ impl Executable for Object { } MethodDefinitionKind::Get => { let set = obj - .get_property(name.clone()) + .get_property(name.clone(), context)? .as_ref() .and_then(|p| p.as_accessor_descriptor()) .and_then(|a| a.setter().cloned()); @@ -116,7 +116,7 @@ impl Executable for Object { } MethodDefinitionKind::Set => { let get = obj - .get_property(name.clone()) + .get_property(name.clone(), context)? .as_ref() .and_then(|p| p.as_accessor_descriptor()) .and_then(|a| a.getter().cloned()); diff --git a/boa/src/syntax/ast/node/operator/assign/mod.rs b/boa/src/syntax/ast/node/operator/assign/mod.rs index 0696ba81a3c..fff9a3f179e 100644 --- a/boa/src/syntax/ast/node/operator/assign/mod.rs +++ b/boa/src/syntax/ast/node/operator/assign/mod.rs @@ -53,30 +53,24 @@ impl Assign { } impl Executable for Assign { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("Assign", "exec"); let val = self.rhs().run(context)?; match self.lhs() { Node::Identifier(ref name) => { - let environment = &mut context.realm_mut().environment; + let environment = &mut context.realm().environment.borrow(); - if environment.has_binding(name.as_ref()) { + if environment.has_binding(name.as_ref(), context)? { // Binding already exists - environment - .set_mutable_binding(name.as_ref(), val.clone(), true) - .map_err(|e| e.to_error(context))?; + environment.set_mutable_binding(name.as_ref(), val.clone(), true, context)?; } else { - environment - .create_mutable_binding( - name.as_ref().to_owned(), - true, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - let environment = &mut context.realm_mut().environment; - environment - .initialize_binding(name.as_ref(), val.clone()) - .map_err(|e| e.to_error(context))?; + environment.create_mutable_binding( + name.as_ref().to_owned(), + true, + VariableScope::Function, + context, + )?; + environment.initialize_binding(name.as_ref(), val.clone(), context)?; } } Node::GetConstField(ref get_const_field) => { diff --git a/boa/src/syntax/ast/node/operator/bin_op/mod.rs b/boa/src/syntax/ast/node/operator/bin_op/mod.rs index f99e3ed28b3..3d0fc8d076b 100644 --- a/boa/src/syntax/ast/node/operator/bin_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/bin_op/mod.rs @@ -63,7 +63,7 @@ impl BinOp { } /// Runs the assignment operators. - fn run_assign(op: AssignOp, x: Value, y: &Node, context: &mut Context) -> Result { + fn run_assign(op: AssignOp, x: Value, y: &Node, context: &Context) -> Result { match op { AssignOp::Add => x.add(&y.run(context)?, context), AssignOp::Sub => x.sub(&y.run(context)?, context), @@ -103,7 +103,7 @@ impl BinOp { } impl Executable for BinOp { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { match self.op() { op::BinOp::Num(op) => { let x = self.lhs().run(context)?; @@ -149,7 +149,7 @@ impl Executable for BinOp { )); } let key = x.to_property_key(context)?; - context.has_property(&y, &key) + context.has_property(&y, &key)? } CompOp::InstanceOf => { if let Some(object) = y.as_object() { @@ -208,15 +208,15 @@ impl Executable for BinOp { let v_a = context .realm() .environment - .get_binding_value(name.as_ref()) - .map_err(|e| e.to_error(context))?; - + .borrow() + .get_binding_value(name.as_ref(), context)?; let value = Self::run_assign(op, v_a, self.rhs(), context)?; - context - .realm_mut() - .environment - .set_mutable_binding(name.as_ref(), value.clone(), true) - .map_err(|e| e.to_error(context))?; + context.realm().environment.borrow().set_mutable_binding( + name.as_ref(), + value.clone(), + true, + context, + )?; Ok(value) } Node::GetConstField(ref get_const_field) => { diff --git a/boa/src/syntax/ast/node/operator/unary_op/mod.rs b/boa/src/syntax/ast/node/operator/unary_op/mod.rs index 545a7dc8e4d..aa7fe2ce31e 100644 --- a/boa/src/syntax/ast/node/operator/unary_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/unary_op/mod.rs @@ -54,7 +54,7 @@ impl UnaryOp { } impl Executable for UnaryOp { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let x = self.target().run(context)?; Ok(match self.op() { @@ -97,14 +97,14 @@ impl Executable for UnaryOp { .obj() .run(context)? .to_object(context)? - .delete(&get_const_field.field().into()), + .delete(&get_const_field.field().into(), context)?, ), Node::GetField(ref get_field) => { let obj = get_field.obj().run(context)?; let field = &get_field.field().run(context)?; let res = obj .to_object(context)? - .delete(&field.to_property_key(context)?); + .delete(&field.to_property_key(context)?, context)?; return Ok(Value::boolean(res)); } Node::Identifier(_) => Value::boolean(false), diff --git a/boa/src/syntax/ast/node/return_smt/mod.rs b/boa/src/syntax/ast/node/return_smt/mod.rs index 6201624b52c..5356d75f666 100644 --- a/boa/src/syntax/ast/node/return_smt/mod.rs +++ b/boa/src/syntax/ast/node/return_smt/mod.rs @@ -58,7 +58,7 @@ impl Return { } impl Executable for Return { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let result = match self.expr() { Some(ref v) => v.run(context), None => Ok(Value::undefined()), @@ -66,6 +66,7 @@ impl Executable for Return { // Set flag for return context .executor() + .borrow_mut() .set_current_state(InterpreterState::Return); result } diff --git a/boa/src/syntax/ast/node/spread/mod.rs b/boa/src/syntax/ast/node/spread/mod.rs index b79292ebab3..c61b973a2c6 100644 --- a/boa/src/syntax/ast/node/spread/mod.rs +++ b/boa/src/syntax/ast/node/spread/mod.rs @@ -52,7 +52,7 @@ impl Spread { } impl Executable for Spread { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { // TODO: for now we can do nothing but return the value as-is self.val().run(context) } diff --git a/boa/src/syntax/ast/node/statement_list/mod.rs b/boa/src/syntax/ast/node/statement_list/mod.rs index 563eafbda83..57c4d2bccbe 100644 --- a/boa/src/syntax/ast/node/statement_list/mod.rs +++ b/boa/src/syntax/ast/node/statement_list/mod.rs @@ -58,18 +58,21 @@ impl StatementList { } impl Executable for StatementList { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("StatementList", "exec"); // https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation // The return value is uninitialized, which means it defaults to Value::Undefined let mut obj = Value::default(); - context - .executor() - .set_current_state(InterpreterState::Executing); + { + context + .executor() + .borrow_mut() + .set_current_state(InterpreterState::Executing); + } for (i, item) in self.items().iter().enumerate() { let val = item.run(context)?; - match context.executor().get_current_state() { + match context.executor().borrow().get_current_state() { InterpreterState::Return => { // Early return. obj = val; diff --git a/boa/src/syntax/ast/node/switch/mod.rs b/boa/src/syntax/ast/node/switch/mod.rs index f62de5ae109..f91a3a26aea 100644 --- a/boa/src/syntax/ast/node/switch/mod.rs +++ b/boa/src/syntax/ast/node/switch/mod.rs @@ -122,25 +122,27 @@ impl Switch { } impl Executable for Switch { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let val = self.val().run(context)?; let mut result = Value::null(); let mut matched = false; - context - .executor() - .set_current_state(InterpreterState::Executing); - + { + context + .executor() + .borrow_mut() + .set_current_state(InterpreterState::Executing); + } // If a case block does not end with a break statement then subsequent cases will be run without // checking their conditions until a break is encountered. let mut fall_through: bool = false; - for case in self.cases().iter() { let cond = case.condition(); let block = case.body(); if fall_through || val.strict_equals(&cond.run(context)?) { matched = true; let result = block.run(context)?; - match context.executor().get_current_state() { + let executor = &mut context.executor().borrow_mut(); + match executor.get_current_state() { InterpreterState::Return => { // Early return. return Ok(result); @@ -148,9 +150,7 @@ impl Executable for Switch { InterpreterState::Break(_label) => { // TODO, break to a label. // Break statement encountered so therefore end switch statement. - context - .executor() - .set_current_state(InterpreterState::Executing); + executor.set_current_state(InterpreterState::Executing); break; } InterpreterState::Continue(_label) => { @@ -169,10 +169,11 @@ impl Executable for Switch { if let Some(default) = self.default() { context .executor() + .borrow_mut() .set_current_state(InterpreterState::Executing); for (i, item) in default.iter().enumerate() { let val = item.run(context)?; - match context.executor().get_current_state() { + match context.executor().borrow().get_current_state() { InterpreterState::Return => { // Early return. result = val; diff --git a/boa/src/syntax/ast/node/template/mod.rs b/boa/src/syntax/ast/node/template/mod.rs index 89ad2dbbcae..04e113f32c2 100644 --- a/boa/src/syntax/ast/node/template/mod.rs +++ b/boa/src/syntax/ast/node/template/mod.rs @@ -32,7 +32,7 @@ impl TemplateLit { } impl Executable for TemplateLit { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("TemplateLiteral", "exec"); let mut result = String::new(); @@ -85,7 +85,7 @@ impl TaggedTemplate { } impl Executable for TaggedTemplate { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("TaggedTemplate", "exec"); let template_object = Array::new_array(context)?; diff --git a/boa/src/syntax/ast/node/throw/mod.rs b/boa/src/syntax/ast/node/throw/mod.rs index 486b5129439..e4e0ff99458 100644 --- a/boa/src/syntax/ast/node/throw/mod.rs +++ b/boa/src/syntax/ast/node/throw/mod.rs @@ -47,7 +47,7 @@ impl Throw { impl Executable for Throw { #[inline] - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { Err(self.expr().run(context)?) } } diff --git a/boa/src/syntax/ast/node/try_node/mod.rs b/boa/src/syntax/ast/node/try_node/mod.rs index ea90741a5ed..08d08b593d0 100644 --- a/boa/src/syntax/ast/node/try_node/mod.rs +++ b/boa/src/syntax/ast/node/try_node/mod.rs @@ -92,34 +92,31 @@ impl Try { } impl Executable for Try { - fn run(&self, context: &mut Context) -> Result { + fn run(&self, context: &Context) -> Result { let _timer = BoaProfiler::global().start_event("Try", "exec"); let res = self.block().run(context).map_or_else( |err| { if let Some(catch) = self.catch() { { - let env = &mut context.realm_mut().environment; - env.push(new_declarative_environment(Some( - env.get_current_environment_ref().clone(), - ))); + let env = &mut context.realm().environment.borrow(); + let current_env = env.get_current_environment(); + env.push(new_declarative_environment(Some(current_env))); if let Some(param) = catch.parameter() { env.create_mutable_binding( param.to_owned(), false, VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - let env = &mut context.realm_mut().environment; - env.initialize_binding(param, err) - .map_err(|e| e.to_error(context))?; + context, + )?; + env.initialize_binding(param, err, context)?; } } let res = catch.block().run(context); // pop the block env - let _ = context.realm_mut().environment.pop(); + let _ = context.realm().environment.borrow().pop(); res } else { diff --git a/boa/src/value/display.rs b/boa/src/value/display.rs index 801d8b22357..594a844659c 100644 --- a/boa/src/value/display.rs +++ b/boa/src/value/display.rs @@ -2,8 +2,9 @@ use super::*; /// This object is used for displaying a `Value`. #[derive(Debug, Clone, Copy)] -pub struct ValueDisplay<'value> { - pub(super) value: &'value Value, +pub struct ValueDisplay<'a> { + pub(super) value: &'a Value, + pub(super) context: &'a Context, } /// A helper macro for printing objects @@ -15,10 +16,10 @@ pub struct ValueDisplay<'value> { /// - A HashSet with the addresses of the already printed objects for the current branch /// (used to avoid infinite loops when there are cyclic deps) macro_rules! print_obj_value { - (all of $obj:expr, $display_fn:ident, $indent:expr, $encounters:expr) => { + (all of $obj:expr, $display_fn:ident, $indent:expr, $encounters:expr, $context:ident) => { { - let mut internals = print_obj_value!(internals of $obj, $display_fn, $indent, $encounters); - let mut props = print_obj_value!(props of $obj, $display_fn, $indent, $encounters, true); + let mut internals = print_obj_value!(internals of $obj, $display_fn, $indent, $encounters, $context); + let mut props = print_obj_value!(props of $obj, $display_fn, $indent, $encounters, true, $context); props.reserve(internals.len()); props.append(&mut internals); @@ -26,27 +27,27 @@ macro_rules! print_obj_value { props } }; - (internals of $obj:expr, $display_fn:ident, $indent:expr, $encounters:expr) => { + (internals of $obj:expr, $display_fn:ident, $indent:expr, $encounters:expr, $context:ident) => { { let object = $obj.borrow(); if object.prototype_instance().is_object() { vec![format!( "{:>width$}: {}", "__proto__", - $display_fn(object.prototype_instance(), $encounters, $indent.wrapping_add(4), true), + $display_fn(object.prototype_instance(), $encounters, $indent.wrapping_add(4), true, $context), width = $indent, )] } else { vec![format!( "{:>width$}: {}", "__proto__", - object.prototype_instance().display(), + object.prototype_instance().display($context), width = $indent, )] } } }; - (props of $obj:expr, $display_fn:ident, $indent:expr, $encounters:expr, $print_internals:expr) => { + (props of $obj:expr, $display_fn:ident, $indent:expr, $encounters:expr, $print_internals:expr, $context:ident) => { print_obj_value!(impl $obj, |(key, val)| { if val.is_data_descriptor() { let v = &val @@ -56,7 +57,7 @@ macro_rules! print_obj_value { format!( "{:>width$}: {}", key, - $display_fn(v, $encounters, $indent.wrapping_add(4), $print_internals), + $display_fn(v, $encounters, $indent.wrapping_add(4), $print_internals, $context), width = $indent, ) } else { @@ -83,7 +84,12 @@ macro_rules! print_obj_value { }; } -pub(crate) fn log_string_from(x: &Value, print_internals: bool, print_children: bool) -> String { +pub(crate) fn log_string_from( + x: &Value, + print_internals: bool, + print_children: bool, + context: &Context, +) -> String { match x { // We don't want to print private (compiler) or prototype properties Value::Object(ref v) => { @@ -102,7 +108,8 @@ pub(crate) fn log_string_from(x: &Value, print_internals: bool, print_children: } ObjectData::Array => { let len = v - .get_own_property(&PropertyKey::from("length")) + .get_own_property(&PropertyKey::from("length"), context) + .unwrap() // TODO: do this in a better way `unwrap` .unwrap() // FIXME: handle accessor descriptors @@ -123,12 +130,14 @@ pub(crate) fn log_string_from(x: &Value, print_internals: bool, print_children: // Introduce recursive call to stringify any objects // which are part of the Array log_string_from( - &v.get_own_property(&i.into()) + &v.get_own_property(&i.into(), context) + .unwrap() // FIXME: handle accessor descriptors .and_then(|p| p.as_data_descriptor().map(|d| d.value())) .unwrap_or_default(), print_internals, false, + context, ) }) .collect::>() @@ -141,7 +150,8 @@ pub(crate) fn log_string_from(x: &Value, print_internals: bool, print_children: } ObjectData::Map(ref map) => { let size = v - .get_own_property(&PropertyKey::from("size")) + .get_own_property(&PropertyKey::from("size"), context) + .unwrap() // TODO: do this in a better way "unwrap" .unwrap() // FIXME: handle accessor descriptors @@ -158,8 +168,8 @@ pub(crate) fn log_string_from(x: &Value, print_internals: bool, print_children: let mappings = map .iter() .map(|(key, value)| { - let key = log_string_from(key, print_internals, false); - let value = log_string_from(value, print_internals, false); + let key = log_string_from(key, print_internals, false, context); + let value = log_string_from(value, print_internals, false, context); format!("{} → {}", key, value) }) .collect::>() @@ -169,16 +179,16 @@ pub(crate) fn log_string_from(x: &Value, print_internals: bool, print_children: format!("Map({})", size) } } - _ => display_obj(&x, print_internals), + _ => display_obj(&x, print_internals, context), } } Value::Symbol(ref symbol) => symbol.to_string(), - _ => format!("{}", x.display()), + _ => format!("{}", x.display(&context)), } } /// A helper function for specifically printing object values -pub(crate) fn display_obj(v: &Value, print_internals: bool) -> String { +pub(crate) fn display_obj(v: &Value, print_internals: bool, context: &Context) -> String { // A simple helper for getting the address of a value // TODO: Find a more general place for this, as it can be used in other situations as well fn address_of(t: &T) -> usize { @@ -193,18 +203,20 @@ pub(crate) fn display_obj(v: &Value, print_internals: bool) -> String { if let Value::Object(object) = v { if object.borrow().is_error() { let name = v - .get_property("name") + .get_property("name", context) + .unwrap() .as_ref() .and_then(|p| p.as_data_descriptor()) .map(|d| d.value()) .unwrap_or_else(Value::undefined); let message = v - .get_property("message") + .get_property("message", context) + .unwrap() .as_ref() .and_then(|p| p.as_data_descriptor()) .map(|d| d.value()) .unwrap_or_else(Value::undefined); - return format!("{}: {}", name.display(), message.display()); + return format!("{}: {}", name.display(context), message.display(context)); } } @@ -213,6 +225,7 @@ pub(crate) fn display_obj(v: &Value, print_internals: bool) -> String { encounters: &mut HashSet, indent: usize, print_internals: bool, + context: &Context, ) -> String { if let Value::Object(ref v) = *data { // The in-memory address of the current object @@ -228,9 +241,10 @@ pub(crate) fn display_obj(v: &Value, print_internals: bool) -> String { encounters.insert(addr); let result = if print_internals { - print_obj_value!(all of v, display_obj_internal, indent, encounters).join(",\n") + print_obj_value!(all of v, display_obj_internal, indent, encounters, context) + .join(",\n") } else { - print_obj_value!(props of v, display_obj_internal, indent, encounters, print_internals) + print_obj_value!(props of v, display_obj_internal, indent, encounters, print_internals, context) .join(",\n") }; @@ -244,11 +258,11 @@ pub(crate) fn display_obj(v: &Value, print_internals: bool) -> String { format!("{{\n{}\n{}}}", result, closing_indent) } else { // Every other type of data is printed with the display method - format!("{}", data.display()) + format!("{}", data.display(context)) } } - display_obj_internal(v, &mut encounters, 4, print_internals) + display_obj_internal(v, &mut encounters, 4, print_internals, context) } impl Display for ValueDisplay<'_> { @@ -263,7 +277,11 @@ impl Display for ValueDisplay<'_> { }, Value::String(ref v) => write!(f, "\"{}\"", v), Value::Rational(v) => format_rational(*v, f), - Value::Object(_) => write!(f, "{}", log_string_from(self.value, true, true)), + Value::Object(_) => write!( + f, + "{}", + log_string_from(self.value, true, true, self.context) + ), Value::Integer(v) => write!(f, "{}", v), Value::BigInt(ref num) => write!(f, "{}n", num), } diff --git a/boa/src/value/equality.rs b/boa/src/value/equality.rs index 86b8adbe176..364a8486916 100644 --- a/boa/src/value/equality.rs +++ b/boa/src/value/equality.rs @@ -37,7 +37,7 @@ impl Value { /// This method is executed when doing abstract equality comparisons with the `==` operator. /// For more information, check #[allow(clippy::float_cmp)] - pub fn equals(&self, other: &Self, context: &mut Context) -> Result { + pub fn equals(&self, other: &Self, context: &Context) -> Result { // 1. If Type(x) is the same as Type(y), then // a. Return the result of performing Strict Equality Comparison x === y. if self.get_type() == other.get_type() { diff --git a/boa/src/value/mod.rs b/boa/src/value/mod.rs index bada012b55b..9a81317b791 100644 --- a/boa/src/value/mod.rs +++ b/boa/src/value/mod.rs @@ -164,7 +164,7 @@ impl Value { } /// Convert from a JSON value to a JS value - pub fn from_json(json: JSONValue, context: &mut Context) -> Self { + pub fn from_json(json: JSONValue, context: &Context) -> Self { match json { JSONValue::Number(v) => { if let Some(Ok(integer_32)) = v.as_i64().map(i32::try_from) { @@ -215,7 +215,7 @@ impl Value { } /// Converts the `Value` to `JSON`. - pub fn to_json(&self, context: &mut Context) -> Result { + pub fn to_json(&self, context: &Context) -> Result { let to_json = self.get_field("toJSON", context)?; if to_json.is_function() { let json_value = context.call(&to_json, self, &[])?; @@ -256,8 +256,11 @@ impl Value { /// /// would turn `extensible` to `false` /// would also turn `extensible` to `false` - pub fn is_extensible(&self) -> bool { - true + pub fn is_extensible(&self, context: &Context) -> Result { + match self { + Value::Object(object) => object.is_extensible(context), + _ => Ok(false), + } } /// Returns true if the value the global for a Realm @@ -433,7 +436,11 @@ impl Value { /// Resolve the property in the object. /// /// A copy of the Property is returned. - pub fn get_property(&self, key: Key) -> Option + pub fn get_property( + &self, + key: Key, + context: &Context, + ) -> Result> where Key: Into, { @@ -441,21 +448,24 @@ impl Value { let _timer = BoaProfiler::global().start_event("Value::get_property", "value"); match self { Self::Object(ref object) => { - let property = object.get_own_property(&key); + let property = object.get_own_property(&key, context)?; if property.is_some() { - return property; + return Ok(property); } - object.borrow().prototype_instance().get_property(key) + object + .borrow() + .prototype_instance() + .get_property(key, context) } - _ => None, + _ => Ok(None), } } /// Resolve the property in the object and get its value, or undefined if this is not an object or the field doesn't exist /// get_field receives a Property from get_prop(). It should then return the `[[Get]]` result value if that's set, otherwise fall back to `[[Value]]` /// TODO: this function should use the get Value if its set - pub fn get_field(&self, key: K, context: &mut Context) -> Result + pub fn get_field(&self, key: K, context: &Context) -> Result where K: Into, { @@ -469,19 +479,21 @@ impl Value { /// Check to see if the Value has the field, mainly used by environment records. #[inline] - pub fn has_field(&self, key: K) -> bool + pub fn has_field(&self, key: K, context: &Context) -> Result where K: Into, { let _timer = BoaProfiler::global().start_event("Value::has_field", "value"); - self.as_object() - .map(|object| object.has_property(&key.into())) - .unwrap_or(false) + Ok(self + .as_object() + .map(|object| object.has_property(&key.into(), context)) + .transpose()? + .unwrap_or(false)) } /// Set the field in the value #[inline] - pub fn set_field(&self, key: K, value: V, context: &mut Context) -> Result + pub fn set_field(&self, key: K, value: V, context: &Context) -> Result where K: Into, V: Into, @@ -519,11 +531,7 @@ impl Value { /// The abstract operation ToPrimitive takes an input argument and an optional argument PreferredType. /// /// - pub fn to_primitive( - &self, - context: &mut Context, - preferred_type: PreferredType, - ) -> Result { + pub fn to_primitive(&self, context: &Context, preferred_type: PreferredType) -> Result { // 1. Assert: input is an ECMAScript language value. (always a value not need to check) // 2. If Type(input) is Object, then if let Value::Object(obj) = self { @@ -561,7 +569,7 @@ impl Value { /// Converts the value to a `BigInt`. /// /// This function is equivelent to `BigInt(value)` in JavaScript. - pub fn to_bigint(&self, context: &mut Context) -> Result { + pub fn to_bigint(&self, context: &Context) -> Result { match self { Value::Null => Err(context.construct_type_error("cannot convert null to a BigInt")), Value::Undefined => { @@ -597,20 +605,23 @@ impl Value { /// /// ``` /// use boa::Value; - /// + /// let context = Context::new(); /// let value = Value::number(3); /// - /// println!("{}", value.display()); + /// println!("{}", value.display(context)); /// ``` #[inline] - pub fn display(&self) -> ValueDisplay<'_> { - ValueDisplay { value: self } + pub fn display<'a>(&'a self, context: &'a Context) -> ValueDisplay<'a> { + ValueDisplay { + value: self, + context, + } } /// Converts the value to a string. /// /// This function is equivalent to `String(value)` in JavaScript. - pub fn to_string(&self, context: &mut Context) -> Result { + pub fn to_string(&self, context: &Context) -> Result { match self { Value::Null => Ok("null".into()), Value::Undefined => Ok("undefined".into()), @@ -632,7 +643,7 @@ impl Value { /// This function is equivalent to `Object(value)` in JavaScript /// /// See: - pub fn to_object(&self, context: &mut Context) -> Result { + pub fn to_object(&self, context: &Context) -> Result { match self { Value::Undefined | Value::Null => { Err(context.construct_type_error("cannot convert 'null' or 'undefined' to object")) @@ -694,7 +705,7 @@ impl Value { /// Converts the value to a `PropertyKey`, that can be used as a key for properties. /// /// See - pub fn to_property_key(&self, context: &mut Context) -> Result { + pub fn to_property_key(&self, context: &Context) -> Result { Ok(match self { // Fast path: Value::String(string) => string.clone().into(), @@ -711,7 +722,7 @@ impl Value { /// It returns value converted to a numeric value of type `Number` or `BigInt`. /// /// See: - pub fn to_numeric(&self, context: &mut Context) -> Result { + pub fn to_numeric(&self, context: &Context) -> Result { let primitive = self.to_primitive(context, PreferredType::Number)?; if let Some(bigint) = primitive.as_bigint() { return Ok(bigint.clone().into()); @@ -724,7 +735,7 @@ impl Value { /// This function is equivalent to `value | 0` in JavaScript /// /// See: - pub fn to_u32(&self, context: &mut Context) -> Result { + pub fn to_u32(&self, context: &Context) -> Result { // This is the fast path, if the value is Integer we can just return it. if let Value::Integer(number) = *self { return Ok(number as u32); @@ -737,7 +748,7 @@ impl Value { /// Converts a value to an integral 32 bit signed integer. /// /// See: - pub fn to_i32(&self, context: &mut Context) -> Result { + pub fn to_i32(&self, context: &Context) -> Result { // This is the fast path, if the value is Integer we can just return it. if let Value::Integer(number) = *self { return Ok(number); @@ -750,7 +761,7 @@ impl Value { /// Converts a value to a non-negative integer if it is a valid integer index value. /// /// See: - pub fn to_index(&self, context: &mut Context) -> Result { + pub fn to_index(&self, context: &Context) -> Result { if self.is_undefined() { return Ok(0); } @@ -773,7 +784,7 @@ impl Value { /// Converts argument to an integer suitable for use as the length of an array-like object. /// /// See: - pub fn to_length(&self, context: &mut Context) -> Result { + pub fn to_length(&self, context: &Context) -> Result { // 1. Let len be ? ToInteger(argument). let len = self.to_integer(context)?; @@ -789,7 +800,7 @@ impl Value { /// Converts a value to an integral Number value. /// /// See: - pub fn to_integer(&self, context: &mut Context) -> Result { + pub fn to_integer(&self, context: &Context) -> Result { // 1. Let number be ? ToNumber(argument). let number = self.to_number(context)?; @@ -813,7 +824,7 @@ impl Value { /// This function is equivalent to the unary `+` operator (`+value`) in JavaScript /// /// See: - pub fn to_number(&self, context: &mut Context) -> Result { + pub fn to_number(&self, context: &Context) -> Result { match *self { Value::Null => Ok(0.0), Value::Undefined => Ok(f64::NAN), @@ -841,7 +852,7 @@ impl Value { /// This function is equivalent to `Number(value)` in JavaScript /// /// See: - pub fn to_numeric_number(&self, context: &mut Context) -> Result { + pub fn to_numeric_number(&self, context: &Context) -> Result { let primitive = self.to_primitive(context, PreferredType::Number)?; if let Some(ref bigint) = primitive.as_bigint() { return Ok(bigint.to_f64()); @@ -861,7 +872,7 @@ impl Value { /// [table]: https://tc39.es/ecma262/#table-14 /// [spec]: https://tc39.es/ecma262/#sec-requireobjectcoercible #[inline] - pub fn require_object_coercible(&self, context: &mut Context) -> Result<&Value> { + pub fn require_object_coercible(&self, context: &Context) -> Result<&Value> { if self.is_null_or_undefined() { Err(context.construct_type_error("cannot convert null or undefined to Object")) } else { @@ -870,7 +881,7 @@ impl Value { } #[inline] - pub fn to_property_descriptor(&self, context: &mut Context) -> Result { + pub fn to_property_descriptor(&self, context: &Context) -> Result { if let Self::Object(ref object) = self { object.to_property_descriptor(context) } else { @@ -881,7 +892,7 @@ impl Value { /// Converts argument to an integer, +∞, or -∞. /// /// See: - pub fn to_integer_or_infinity(&self, context: &mut Context) -> Result { + pub fn to_integer_or_infinity(&self, context: &Context) -> Result { // 1. Let number be ? ToNumber(argument). let number = self.to_number(context)?; diff --git a/boa/src/value/operations.rs b/boa/src/value/operations.rs index 44cc173f8b3..23fa597a84a 100644 --- a/boa/src/value/operations.rs +++ b/boa/src/value/operations.rs @@ -3,7 +3,7 @@ use crate::builtins::number::{f64_to_int32, f64_to_uint32, Number}; impl Value { #[inline] - pub fn add(&self, other: &Self, context: &mut Context) -> Result { + pub fn add(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => Self::rational(f64::from(*x) + f64::from(*y)), @@ -45,7 +45,7 @@ impl Value { } #[inline] - pub fn sub(&self, other: &Self, context: &mut Context) -> Result { + pub fn sub(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => Self::rational(f64::from(*x) - f64::from(*y)), @@ -73,7 +73,7 @@ impl Value { } #[inline] - pub fn mul(&self, other: &Self, context: &mut Context) -> Result { + pub fn mul(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => Self::rational(f64::from(*x) * f64::from(*y)), @@ -101,7 +101,7 @@ impl Value { } #[inline] - pub fn div(&self, other: &Self, context: &mut Context) -> Result { + pub fn div(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => Self::rational(f64::from(*x) / f64::from(*y)), @@ -135,7 +135,7 @@ impl Value { } #[inline] - pub fn rem(&self, other: &Self, context: &mut Context) -> Result { + pub fn rem(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => { @@ -172,7 +172,7 @@ impl Value { } #[inline] - pub fn pow(&self, other: &Self, context: &mut Context) -> Result { + pub fn pow(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => Self::rational(f64::from(*x).powi(*y)), @@ -206,7 +206,7 @@ impl Value { } #[inline] - pub fn bitand(&self, other: &Self, context: &mut Context) -> Result { + pub fn bitand(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => Self::integer(x & y), @@ -238,7 +238,7 @@ impl Value { } #[inline] - pub fn bitor(&self, other: &Self, context: &mut Context) -> Result { + pub fn bitor(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => Self::integer(x | y), @@ -270,7 +270,7 @@ impl Value { } #[inline] - pub fn bitxor(&self, other: &Self, context: &mut Context) -> Result { + pub fn bitxor(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => Self::integer(x ^ y), @@ -302,7 +302,7 @@ impl Value { } #[inline] - pub fn shl(&self, other: &Self, context: &mut Context) -> Result { + pub fn shl(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => Self::integer(x.wrapping_shl(*y as u32)), @@ -344,7 +344,7 @@ impl Value { } #[inline] - pub fn shr(&self, other: &Self, context: &mut Context) -> Result { + pub fn shr(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => Self::integer(x.wrapping_shr(*y as u32)), @@ -386,7 +386,7 @@ impl Value { } #[inline] - pub fn ushr(&self, other: &Self, context: &mut Context) -> Result { + pub fn ushr(&self, other: &Self, context: &Context) -> Result { Ok(match (self, other) { // Fast path: (Self::Integer(x), Self::Integer(y)) => { @@ -421,7 +421,7 @@ impl Value { } #[inline] - pub fn neg(&self, context: &mut Context) -> Result { + pub fn neg(&self, context: &Context) -> Result { Ok(match *self { Self::Symbol(_) | Self::Undefined => Self::rational(NAN), Self::Object(_) => Self::rational(match self.to_numeric_number(context) { @@ -441,7 +441,7 @@ impl Value { } #[inline] - pub fn not(&self, _: &mut Context) -> Result { + pub fn not(&self, _: &Context) -> Result { Ok(!self.to_boolean()) } @@ -466,7 +466,7 @@ impl Value { &self, other: &Self, left_first: bool, - context: &mut Context, + context: &Context, ) -> Result { Ok(match (self, other) { // Fast path (for some common operations): @@ -565,7 +565,7 @@ impl Value { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than /// [spec]: https://tc39.es/ecma262/#sec-relational-operators-runtime-semantics-evaluation #[inline] - pub fn lt(&self, other: &Self, context: &mut Context) -> Result { + pub fn lt(&self, other: &Self, context: &Context) -> Result { match self.abstract_relation(other, true, context)? { AbstractRelation::True => Ok(true), AbstractRelation::False | AbstractRelation::Undefined => Ok(false), @@ -582,7 +582,7 @@ impl Value { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than_or_equal /// [spec]: https://tc39.es/ecma262/#sec-relational-operators-runtime-semantics-evaluation #[inline] - pub fn le(&self, other: &Self, context: &mut Context) -> Result { + pub fn le(&self, other: &Self, context: &Context) -> Result { match other.abstract_relation(self, false, context)? { AbstractRelation::False => Ok(true), AbstractRelation::True | AbstractRelation::Undefined => Ok(false), @@ -599,7 +599,7 @@ impl Value { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Greater_than /// [spec]: https://tc39.es/ecma262/#sec-relational-operators-runtime-semantics-evaluation #[inline] - pub fn gt(&self, other: &Self, context: &mut Context) -> Result { + pub fn gt(&self, other: &Self, context: &Context) -> Result { match other.abstract_relation(self, false, context)? { AbstractRelation::True => Ok(true), AbstractRelation::False | AbstractRelation::Undefined => Ok(false), @@ -616,7 +616,7 @@ impl Value { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Greater_than_or_equal /// [spec]: https://tc39.es/ecma262/#sec-relational-operators-runtime-semantics-evaluation #[inline] - pub fn ge(&self, other: &Self, context: &mut Context) -> Result { + pub fn ge(&self, other: &Self, context: &Context) -> Result { match self.abstract_relation(other, true, context)? { AbstractRelation::False => Ok(true), AbstractRelation::True | AbstractRelation::Undefined => Ok(false), diff --git a/boa/src/value/tests.rs b/boa/src/value/tests.rs index 81619ffd474..c412ed6abf3 100644 --- a/boa/src/value/tests.rs +++ b/boa/src/value/tests.rs @@ -23,9 +23,10 @@ fn string_to_value() { #[test] fn undefined() { + let context = Context::new(); let u = Value::Undefined; assert_eq!(u.get_type(), Type::Undefined); - assert_eq!(u.display().to_string(), "undefined"); + assert_eq!(u.display(&context).to_string(), "undefined"); } #[test] @@ -38,7 +39,7 @@ fn get_set_field() { assert_eq!( obj.get_field("foo", &mut context) .unwrap() - .display() + .display(&context) .to_string(), "\"bar\"" ); @@ -229,7 +230,8 @@ fn get_types() { #[test] fn to_string() { - let f64_to_str = |f| Value::Rational(f).display().to_string(); + let context = Context::new(); + let f64_to_str = |f| Value::Rational(f).display(&context).to_string(); assert_eq!(f64_to_str(f64::NAN), "NaN"); assert_eq!(f64_to_str(0.0), "0"); @@ -267,7 +269,8 @@ fn string_length_is_not_enumerable() { let object = Value::from("foo").to_object(&mut context).unwrap(); let length_desc = object - .get_own_property(&PropertyKey::from("length")) + .get_own_property(&PropertyKey::from("length"), &context) + .unwrap() .unwrap(); assert!(!length_desc.enumerable()); } @@ -279,7 +282,8 @@ fn string_length_is_in_utf16_codeunits() { // 😀 is one Unicode code point, but 2 UTF-16 code units let object = Value::from("😀").to_object(&mut context).unwrap(); let length_desc = object - .get_own_property(&PropertyKey::from("length")) + .get_own_property(&PropertyKey::from("length"), &context) + .unwrap() .unwrap(); assert_eq!( length_desc @@ -447,9 +451,10 @@ fn assign_pow_number_and_string() { #[test] fn display_string() { + let context = Context::new(); let s = String::from("Hello"); let v = Value::from(s); - assert_eq!(v.display().to_string(), "\"Hello\""); + assert_eq!(v.display(&context).to_string(), "\"Hello\""); } #[test] @@ -457,7 +462,7 @@ fn display_array_string() { let mut context = Context::new(); let value = forward_val(&mut context, "[\"Hello\"]").unwrap(); - assert_eq!(value.display().to_string(), "[ \"Hello\" ]"); + assert_eq!(value.display(&context).to_string(), "[ \"Hello\" ]"); } #[test] @@ -468,7 +473,7 @@ fn display_boolean_object() { bool "#; let value = forward_val(&mut context, d_obj).unwrap(); - assert_eq!(value.display().to_string(), "Boolean { false }") + assert_eq!(value.display(&context).to_string(), "Boolean { false }") } #[test] @@ -479,7 +484,7 @@ fn display_number_object() { num "#; let value = forward_val(&mut context, d_obj).unwrap(); - assert_eq!(value.display().to_string(), "Number { 3.14 }") + assert_eq!(value.display(&context).to_string(), "Number { 3.14 }") } #[test] @@ -490,7 +495,7 @@ fn display_negative_zero_object() { num "#; let value = forward_val(&mut context, d_obj).unwrap(); - assert_eq!(value.display().to_string(), "Number { -0 }") + assert_eq!(value.display(&context).to_string(), "Number { -0 }") } #[test] @@ -516,7 +521,7 @@ fn display_object() { "#; let value = forward_val(&mut context, d_obj).unwrap(); assert_eq!( - value.display().to_string(), + value.display(&context).to_string(), r#"{ a: "a", __proto__: { diff --git a/boa/src/vm/mod.rs b/boa/src/vm/mod.rs index ee831cecdc4..37d49ad6d6d 100644 --- a/boa/src/vm/mod.rs +++ b/boa/src/vm/mod.rs @@ -218,7 +218,7 @@ impl<'a> VM<'a> { )); } let key = l.to_property_key(self.ctx)?; - let val = self.ctx.has_property(&r, &key); + let val = self.ctx.has_property(&r, &key)?; self.push(val.into()); } diff --git a/boa_cli/src/main.rs b/boa_cli/src/main.rs index 2abc10d510e..9b905216d0b 100644 --- a/boa_cli/src/main.rs +++ b/boa_cli/src/main.rs @@ -152,8 +152,8 @@ pub fn main() -> Result<(), std::io::Error> { } } else { match context.eval(&buffer) { - Ok(v) => println!("{}", v.display()), - Err(v) => eprintln!("Uncaught {}", v.display()), + Ok(v) => println!("{}", v.display(&context)), + Err(v) => eprintln!("Uncaught {}", v.display(&context)), } } } @@ -188,9 +188,13 @@ pub fn main() -> Result<(), std::io::Error> { } } else { match context.eval(line.trim_end()) { - Ok(v) => println!("{}", v.display()), + Ok(v) => println!("{}", v.display(&context)), Err(v) => { - eprintln!("{}: {}", "Uncaught".red(), v.display().to_string().red()) + eprintln!( + "{}: {}", + "Uncaught".red(), + v.display(&context).to_string().red() + ) } } } diff --git a/boa_tester/src/exec.rs b/boa_tester/src/exec.rs index aa011deec60..4b26b7e5d34 100644 --- a/boa_tester/src/exec.rs +++ b/boa_tester/src/exec.rs @@ -132,8 +132,8 @@ impl Test { let passed = res.is_ok(); let text = match res { - Ok(val) => format!("{}", val.display()), - Err(e) => format!("Uncaught {}", e.display()), + Ok(val) => format!("{}", val.display(&context)), + Err(e) => format!("Uncaught {}", e.display(&context)), }; (passed, text) @@ -174,12 +174,14 @@ impl Test { } else { match self.set_up_env(&harness, strict) { Ok(mut context) => match context.eval(&self.content.as_ref()) { - Ok(res) => (false, format!("{}", res.display())), + Ok(res) => (false, format!("{}", res.display(&context))), Err(e) => { - let passed = - e.display().to_string().contains(error_type.as_ref()); + let passed = e + .display(&context) + .to_string() + .contains(error_type.as_ref()); - (passed, format!("Uncaught {}", e.display())) + (passed, format!("Uncaught {}", e.display(&context))) } }, Err(e) => (false, e), @@ -259,7 +261,7 @@ impl Test { .map_err(|e| { format!( "could not register the global print() function:\n{}", - e.display() + e.display(&context) ) })?; // TODO: add the $262 object. @@ -267,15 +269,15 @@ impl Test { if strict { context .eval(r#""use strict";"#) - .map_err(|e| format!("could not set strict mode:\n{}", e.display()))?; + .map_err(|e| format!("could not set strict mode:\n{}", e.display(&context)))?; } context .eval(&harness.assert.as_ref()) - .map_err(|e| format!("could not run assert.js:\n{}", e.display()))?; + .map_err(|e| format!("could not run assert.js:\n{}", e.display(&context)))?; context .eval(&harness.sta.as_ref()) - .map_err(|e| format!("could not run sta.js:\n{}", e.display()))?; + .map_err(|e| format!("could not run sta.js:\n{}", e.display(&context)))?; for include in self.includes.iter() { context @@ -290,7 +292,7 @@ impl Test { format!( "could not run the {} include file:\nUncaught {}", include, - e.display() + e.display(&context) ) })?; } @@ -300,6 +302,6 @@ impl Test { } /// `print()` function required by the test262 suite. -fn test262_print(_this: &Value, _: &[Value], _context: &mut Context) -> boa::Result { +fn test262_print(_this: &Value, _: &[Value], _context: &Context) -> boa::Result { todo!("print() function"); } diff --git a/boa_wasm/src/lib.rs b/boa_wasm/src/lib.rs index 1b90a1f54b7..ed15744d02f 100644 --- a/boa_wasm/src/lib.rs +++ b/boa_wasm/src/lib.rs @@ -4,7 +4,7 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn evaluate(src: &str) -> Result { // Setup executor - let mut context = Context::new(); + let context = Context::new(); let expr = match parse(src, false) { Ok(res) => res, @@ -14,12 +14,12 @@ pub fn evaluate(src: &str) -> Result { context .throw_syntax_error(e.to_string()) .expect_err("interpreter.throw_syntax_error() did not return an error") - .display() + .display(&context) ) .into()); } }; - expr.run(&mut context) - .map_err(|e| JsValue::from(format!("Uncaught {}", e.display()))) - .map(|v| v.display().to_string()) + expr.run(&context) + .map_err(|e| JsValue::from(format!("Uncaught {}", e.display(&context)))) + .map(|v| v.display(&context).to_string()) } From 5929b08b94156400d639b83a6071e9088764db3b Mon Sep 17 00:00:00 2001 From: tofpie Date: Sun, 17 Jan 2021 14:51:09 +0100 Subject: [PATCH 2/4] Fix doc tests --- boa/src/value/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/boa/src/value/mod.rs b/boa/src/value/mod.rs index 9a81317b791..fe8c7f99f52 100644 --- a/boa/src/value/mod.rs +++ b/boa/src/value/mod.rs @@ -604,11 +604,12 @@ impl Value { /// # Examples /// /// ``` - /// use boa::Value; + /// use boa::{Context, Value}; + /// /// let context = Context::new(); /// let value = Value::number(3); /// - /// println!("{}", value.display(context)); + /// println!("{}", value.display(&context)); /// ``` #[inline] pub fn display<'a>(&'a self, context: &'a Context) -> ValueDisplay<'a> { From 5254405d859f1bcfea3e0570d8ca9898574054d3 Mon Sep 17 00:00:00 2001 From: tofpie Date: Sun, 17 Jan 2021 15:47:00 +0100 Subject: [PATCH 3/4] Fix bad merge --- boa/src/realm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/realm.rs b/boa/src/realm.rs index 73c7e400fa2..9e2f049b8d0 100644 --- a/boa/src/realm.rs +++ b/boa/src/realm.rs @@ -47,7 +47,7 @@ impl Realm { Self { global_object: gc_global.clone(), global_env, - environment: RefCell::LexicalEnvironment::new(gc_global.into()), + environment: RefCell::new(LexicalEnvironment::new(gc_global.into())), } } } From bc0ec66ffe8c91cae5437e08e60f0faccf65b3f9 Mon Sep 17 00:00:00 2001 From: tofpie Date: Mon, 18 Jan 2021 19:03:38 +0100 Subject: [PATCH 4/4] Implement suggestions from review --- boa/src/builtins/json/mod.rs | 2 +- boa/src/context.rs | 6 +----- boa/src/object/internal_methods.rs | 5 +++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/boa/src/builtins/json/mod.rs b/boa/src/builtins/json/mod.rs index 90872e3646e..81ea955bfc1 100644 --- a/boa/src/builtins/json/mod.rs +++ b/boa/src/builtins/json/mod.rs @@ -224,7 +224,7 @@ impl Json { Some( replacer .get_property(key, context) - .unwrap() + .expect("'key' is one of the keys of 'replacer'") .as_ref() .and_then(|p| p.as_data_descriptor()) .map(|d| d.value()) diff --git a/boa/src/context.rs b/boa/src/context.rs index 13b1dd7880d..148b4b184c3 100644 --- a/boa/src/context.rs +++ b/boa/src/context.rs @@ -555,11 +555,7 @@ impl Context { let array = Value::new_object(self); array.set_data(ObjectData::Array); array.as_object().expect("object").set_prototype_instance( - self.realm() - .environment - .borrow() - .get_binding_value("Array", self)? - .get_field(PROTOTYPE, self)?, + self.standard_objects().array_object().prototype().into(), ); array.set_field(0, key, self)?; array.set_field(1, value, self)?; diff --git a/boa/src/object/internal_methods.rs b/boa/src/object/internal_methods.rs index 2d6ce3a925c..ec769153b22 100644 --- a/boa/src/object/internal_methods.rs +++ b/boa/src/object/internal_methods.rs @@ -88,6 +88,7 @@ impl GcObject { self.borrow_mut().extensible = false; Ok(true) } + /// Delete a property. /// /// More information: @@ -588,12 +589,12 @@ impl GcObject { self.borrow().keys().collect() } - /// OwnPropertyKeys for ordinary objects + /// OwnPropertyKeys for string exotic objects /// /// More information: /// - [ECMAScript reference][spec] /// - /// [spec]: https://tc39.es/ecma262/#sec-ordinaryownpropertykeys + /// [spec]: https://tc39.es/ecma262/#sec-string-exotic-objects-ownpropertykeys pub fn string_own_property_keys(&self) -> Vec { let string = self.borrow().as_string().unwrap(); let mut property_keys = Vec::new();