From e9f61a0752fd6fa2a4ea341473476f25ab8da2fb Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Fri, 22 May 2020 12:58:37 +0200 Subject: [PATCH 1/5] Initial function object constructable/callable fix --- boa/src/builtins/array/mod.rs | 2 +- boa/src/builtins/bigint/mod.rs | 18 +-- boa/src/builtins/boolean/mod.rs | 2 +- boa/src/builtins/error.rs | 3 +- boa/src/builtins/function/mod.rs | 226 +++++++++++++++++-------------- boa/src/builtins/number/mod.rs | 2 +- boa/src/builtins/object/mod.rs | 2 +- boa/src/builtins/regexp/mod.rs | 2 +- boa/src/builtins/string/mod.rs | 2 +- boa/src/builtins/symbol/mod.rs | 3 +- 10 files changed, 143 insertions(+), 119 deletions(-) diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 4b2b725595a..0235e9e0b89 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -978,7 +978,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(slice, named "slice", with length 2, of prototype); make_builtin_fn!(some, named "some", with length 2, of prototype); - let array = make_constructor_fn(make_array, global, prototype); + let array = make_constructor_fn(make_array, global, prototype, true, true); // Static Methods make_builtin_fn!(is_array, named "isArray", with length 1, of array); diff --git a/boa/src/builtins/bigint/mod.rs b/boa/src/builtins/bigint/mod.rs index 403aae28d9b..55aeeab29a6 100644 --- a/boa/src/builtins/bigint/mod.rs +++ b/boa/src/builtins/bigint/mod.rs @@ -72,14 +72,14 @@ pub fn to_string(this: &mut Value, args: &[Value], _ctx: &mut Interpreter) -> Re )) } -// /// `BigInt.prototype.valueOf()` -// /// -// /// The `valueOf()` method returns the wrapped primitive value of a Number object. -// /// -// /// More information: -// /// - [ECMAScript reference][spec] -// /// - [MDN documentation][mdn] -// /// +/// `BigInt.prototype.valueOf()` +/// +/// The `valueOf()` method returns the wrapped primitive value of a Number object. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// /// [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 fn value_of(this: &mut Value, _args: &[Value], _ctx: &mut Interpreter) -> ResultValue { @@ -96,7 +96,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(to_string, named "toString", with length 1, of prototype); make_builtin_fn!(value_of, named "valueOf", of prototype); - make_constructor_fn(make_bigint, global, prototype) + make_constructor_fn(make_bigint, global, prototype, false, true) } /// Initialise the `BigInt` object on the global object. diff --git a/boa/src/builtins/boolean/mod.rs b/boa/src/builtins/boolean/mod.rs index 58956cacda2..1e1609cbf4c 100644 --- a/boa/src/builtins/boolean/mod.rs +++ b/boa/src/builtins/boolean/mod.rs @@ -104,7 +104,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(to_string, named "toString", of prototype); make_builtin_fn!(value_of, named "valueOf", of prototype); - make_constructor_fn(construct_boolean, global, prototype) + make_constructor_fn(construct_boolean, global, prototype, true, true) } /// Initialise the `Boolean` object on the global object. diff --git a/boa/src/builtins/error.rs b/boa/src/builtins/error.rs index 35f4e91c44c..a4d49254524 100644 --- a/boa/src/builtins/error.rs +++ b/boa/src/builtins/error.rs @@ -59,7 +59,8 @@ pub fn create(global: &Value) -> Value { prototype.set_field_slice("message", Value::from("")); prototype.set_field_slice("name", Value::from("Error")); make_builtin_fn!(to_string, named "toString", of prototype); - make_constructor_fn(make_error, global, prototype) + + make_constructor_fn(make_error, global, prototype, true, true) } /// Initialise the global object with the `Error` object. diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index 75cf71322fb..052d73d4d1a 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -102,6 +102,10 @@ pub struct Function { pub kind: FunctionKind, // Environment, built-in functions don't need Environments pub environment: Option, + /// Is it constructable + constructable: bool, + /// Is it callable. + callable: bool, } impl Function { @@ -123,6 +127,8 @@ impl Function { params: parameter_list.into(), kind: FunctionKind::Ordinary, this_mode, + constructable: true, + callable: true, } } @@ -139,6 +145,8 @@ impl Function { this_mode: ThisMode::NonLexical, kind: FunctionKind::BuiltIn, environment: None, + constructable: false, + callable: true, } } @@ -153,57 +161,61 @@ impl Function { interpreter: &mut Interpreter, this_obj: &mut Value, ) -> ResultValue { - match self.kind { - FunctionKind::BuiltIn => match &self.body { - FunctionBody::BuiltIn(func) => func(this_obj, args_list, interpreter), - FunctionBody::Ordinary(_) => { - panic!("Builtin function should not have Ordinary Function body") - } - }, - FunctionKind::Ordinary => { - // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment) - // - let local_env = new_function_environment( - this.clone(), - None, - Some(self.environment.as_ref().unwrap().clone()), - BindingStatus::Uninitialized, - ); - - // Add argument bindings to the function environment - for i in 0..self.params.len() { - let param = self.params.get(i).expect("Could not get param"); - // Rest Parameters - if param.is_rest_param { - self.add_rest_param(param, i, args_list, interpreter, &local_env); - break; + if self.callable { + match self.kind { + FunctionKind::BuiltIn => match &self.body { + FunctionBody::BuiltIn(func) => func(this_obj, args_list, interpreter), + FunctionBody::Ordinary(_) => { + panic!("Builtin function should not have Ordinary Function body") + } + }, + FunctionKind::Ordinary => { + // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment) + // + let local_env = new_function_environment( + this.clone(), + None, + Some(self.environment.as_ref().unwrap().clone()), + BindingStatus::Uninitialized, + ); + + // Add argument bindings to the function environment + for i in 0..self.params.len() { + let param = self.params.get(i).expect("Could not get param"); + // Rest Parameters + if param.is_rest_param { + self.add_rest_param(param, i, args_list, interpreter, &local_env); + break; + } + + let value = args_list.get(i).expect("Could not get value"); + self.add_arguments_to_environment(param, value.clone(), &local_env); } - let value = args_list.get(i).expect("Could not get value"); - self.add_arguments_to_environment(param, value.clone(), &local_env); + // Add arguments object + let arguments_obj = create_unmapped_arguments_object(args_list); + local_env + .borrow_mut() + .create_mutable_binding("arguments".to_string(), false); + local_env + .borrow_mut() + .initialize_binding("arguments", arguments_obj); + + interpreter.realm.environment.push(local_env); + + // Call body should be set before reaching here + let result = match &self.body { + FunctionBody::Ordinary(ref body) => interpreter.run(body), + _ => panic!("Ordinary function should not have BuiltIn Function body"), + }; + + // local_env gets dropped here, its no longer needed + interpreter.realm.environment.pop(); + result } - - // Add arguments object - let arguments_obj = create_unmapped_arguments_object(args_list); - local_env - .borrow_mut() - .create_mutable_binding("arguments".to_string(), false); - local_env - .borrow_mut() - .initialize_binding("arguments", arguments_obj); - - interpreter.realm.environment.push(local_env); - - // Call body should be set before reaching here - let result = match &self.body { - FunctionBody::Ordinary(ref body) => interpreter.run(body), - _ => panic!("Ordinary function should not have BuiltIn Function body"), - }; - - // local_env gets dropped here, its no longer needed - interpreter.realm.environment.pop(); - result } + } else { + panic!("not callable"); } } @@ -215,59 +227,63 @@ impl Function { interpreter: &mut Interpreter, this_obj: &mut Value, ) -> ResultValue { - match self.kind { - FunctionKind::BuiltIn => match &self.body { - FunctionBody::BuiltIn(func) => { - func(this_obj, args_list, interpreter).unwrap(); - Ok(this_obj.clone()) - } - FunctionBody::Ordinary(_) => { - panic!("Builtin function should not have Ordinary Function body") - } - }, - FunctionKind::Ordinary => { - // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment) - // - let local_env = new_function_environment( - this.clone(), - Some(this_obj.clone()), - Some(self.environment.as_ref().unwrap().clone()), - BindingStatus::Initialized, - ); - - // Add argument bindings to the function environment - for (i, param) in self.params.iter().enumerate() { - // Rest Parameters - if param.is_rest_param { - self.add_rest_param(param, i, args_list, interpreter, &local_env); - break; + if self.constructable { + match self.kind { + FunctionKind::BuiltIn => match &self.body { + FunctionBody::BuiltIn(func) => { + func(this_obj, args_list, interpreter).unwrap(); + Ok(this_obj.clone()) + } + FunctionBody::Ordinary(_) => { + panic!("Builtin function should not have Ordinary Function body") + } + }, + FunctionKind::Ordinary => { + // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment) + // + let local_env = new_function_environment( + this.clone(), + Some(this_obj.clone()), + Some(self.environment.as_ref().unwrap().clone()), + BindingStatus::Initialized, + ); + + // Add argument bindings to the function environment + for (i, param) in self.params.iter().enumerate() { + // Rest Parameters + if param.is_rest_param { + self.add_rest_param(param, i, args_list, interpreter, &local_env); + break; + } + + let value = args_list.get(i).expect("Could not get value"); + self.add_arguments_to_environment(param, value.clone(), &local_env); } - let value = args_list.get(i).expect("Could not get value"); - self.add_arguments_to_environment(param, value.clone(), &local_env); + // Add arguments object + let arguments_obj = create_unmapped_arguments_object(args_list); + local_env + .borrow_mut() + .create_mutable_binding("arguments".to_string(), false); + local_env + .borrow_mut() + .initialize_binding("arguments", arguments_obj); + + interpreter.realm.environment.push(local_env); + + // Call body should be set before reaching here + let _ = match &self.body { + FunctionBody::Ordinary(ref body) => interpreter.run(body), + _ => panic!("Ordinary function should not have BuiltIn Function body"), + }; + + // local_env gets dropped here, its no longer needed + let binding = interpreter.realm.environment.get_this_binding(); + Ok(binding) } - - // Add arguments object - let arguments_obj = create_unmapped_arguments_object(args_list); - local_env - .borrow_mut() - .create_mutable_binding("arguments".to_string(), false); - local_env - .borrow_mut() - .initialize_binding("arguments", arguments_obj); - - interpreter.realm.environment.push(local_env); - - // Call body should be set before reaching here - let _ = match &self.body { - FunctionBody::Ordinary(ref body) => interpreter.run(body), - _ => panic!("Ordinary function should not have BuiltIn Function body"), - }; - - // local_env gets dropped here, its no longer needed - let binding = interpreter.realm.environment.get_this_binding(); - Ok(binding) } + } else { + panic!("not constructable") } } @@ -372,19 +388,25 @@ pub fn make_function(this: &mut Value, _: &[Value], _: &mut Interpreter) -> Resu pub fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); - make_constructor_fn(make_function, global, prototype) + make_constructor_fn(make_function, global, prototype, true, true) } /// Creates a new constructor function /// /// This utility function handling linking the new Constructor to the prototype. /// So far this is only used by internal functions -pub fn make_constructor_fn(body: NativeFunctionData, global: &Value, proto: Value) -> Value { +pub fn make_constructor_fn( + body: NativeFunctionData, + global: &Value, + proto: Value, + constructable: bool, + callable: bool, +) -> Value { // Create the native function - let constructor_fn = crate::builtins::function::Function::create_builtin( - vec![], - crate::builtins::function::FunctionBody::BuiltIn(body), - ); + let mut constructor_fn = Function::create_builtin(Vec::new(), FunctionBody::BuiltIn(body)); + + constructor_fn.constructable = constructable; + constructor_fn.callable = callable; // Get reference to Function.prototype let func_prototype = global diff --git a/boa/src/builtins/number/mod.rs b/boa/src/builtins/number/mod.rs index 0da8860f5ac..9d88908b861 100644 --- a/boa/src/builtins/number/mod.rs +++ b/boa/src/builtins/number/mod.rs @@ -366,7 +366,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(to_string, named "toString", with length 1, of prototype); make_builtin_fn!(value_of, named "valueOf", of prototype); - make_constructor_fn(make_number, global, prototype) + make_constructor_fn(make_number, global, prototype, true, true) } /// Initialise the `Number` object on the global object. diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 88afd80c24b..31070ae412e 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -614,7 +614,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(has_own_property, named "hasOwnProperty", of prototype); make_builtin_fn!(to_string, named "toString", of prototype); - let object = make_constructor_fn(make_object, global, prototype); + let object = make_constructor_fn(make_object, global, prototype, true, true); object.set_field_slice("length", Value::from(1)); make_builtin_fn!(set_prototype_of, named "setPrototypeOf", with length 2, of object); diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index 521ebf8e51b..dcccd1f19d6 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -476,7 +476,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(get_sticky, named "sticky", of prototype); make_builtin_fn!(get_unicode, named "unicode", of prototype); - make_constructor_fn(make_regexp, global, prototype) + make_constructor_fn(make_regexp, global, prototype, true, true) } /// Initialise the `RegExp` object on the global object. diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index e3c1a665ca5..b93763b0a22 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -1021,7 +1021,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(match_all, named "matchAll", with length 1, of prototype); make_builtin_fn!(replace, named "replace", with length 2, of prototype); - make_constructor_fn(make_string, global, prototype) + make_constructor_fn(make_string, global, prototype, true, true) } /// Initialise the `String` object on the global object. diff --git a/boa/src/builtins/symbol/mod.rs b/boa/src/builtins/symbol/mod.rs index 16cd4c0e17c..86955277693 100644 --- a/boa/src/builtins/symbol/mod.rs +++ b/boa/src/builtins/symbol/mod.rs @@ -93,7 +93,8 @@ pub fn create(global: &Value) -> Value { // Create prototype object let prototype = Value::new_object(Some(global)); make_builtin_fn!(to_string, named "toString", of prototype); - make_constructor_fn(call_symbol, global, prototype) + + make_constructor_fn(call_symbol, global, prototype, true, true) } /// Initialise the `Symbol` object on the global object. From 710b9d2b9909d3a302b19473d141fc9c44ca05bd Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Sat, 23 May 2020 12:16:43 +0200 Subject: [PATCH 2/5] Maded arrow functions non-constructable --- boa/src/builtins/array/mod.rs | 2 +- boa/src/builtins/bigint/mod.rs | 2 +- boa/src/builtins/boolean/mod.rs | 2 +- boa/src/builtins/error.rs | 2 +- boa/src/builtins/function/mod.rs | 49 +++++++++++++++++++++++--------- boa/src/builtins/number/mod.rs | 2 +- boa/src/builtins/object/mod.rs | 14 ++++++--- boa/src/builtins/regexp/mod.rs | 2 +- boa/src/builtins/string/mod.rs | 2 +- boa/src/builtins/symbol/mod.rs | 2 +- boa/src/builtins/value/mod.rs | 2 +- boa/src/exec/mod.rs | 16 +++++++---- 12 files changed, 66 insertions(+), 31 deletions(-) diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 0235e9e0b89..9b614e20498 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -978,7 +978,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(slice, named "slice", with length 2, of prototype); make_builtin_fn!(some, named "some", with length 2, of prototype); - let array = make_constructor_fn(make_array, global, prototype, true, true); + let array = make_constructor_fn(make_array, global, prototype, true); // Static Methods make_builtin_fn!(is_array, named "isArray", with length 1, of array); diff --git a/boa/src/builtins/bigint/mod.rs b/boa/src/builtins/bigint/mod.rs index 55aeeab29a6..192d65dabe5 100644 --- a/boa/src/builtins/bigint/mod.rs +++ b/boa/src/builtins/bigint/mod.rs @@ -96,7 +96,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(to_string, named "toString", with length 1, of prototype); make_builtin_fn!(value_of, named "valueOf", of prototype); - make_constructor_fn(make_bigint, global, prototype, false, true) + make_constructor_fn(make_bigint, global, prototype, false) } /// Initialise the `BigInt` object on the global object. diff --git a/boa/src/builtins/boolean/mod.rs b/boa/src/builtins/boolean/mod.rs index 1e1609cbf4c..7351423d199 100644 --- a/boa/src/builtins/boolean/mod.rs +++ b/boa/src/builtins/boolean/mod.rs @@ -104,7 +104,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(to_string, named "toString", of prototype); make_builtin_fn!(value_of, named "valueOf", of prototype); - make_constructor_fn(construct_boolean, global, prototype, true, true) + make_constructor_fn(construct_boolean, global, prototype, true) } /// Initialise the `Boolean` object on the global object. diff --git a/boa/src/builtins/error.rs b/boa/src/builtins/error.rs index a4d49254524..c003c789d13 100644 --- a/boa/src/builtins/error.rs +++ b/boa/src/builtins/error.rs @@ -60,7 +60,7 @@ pub fn create(global: &Value) -> Value { prototype.set_field_slice("name", Value::from("Error")); make_builtin_fn!(to_string, named "toString", of prototype); - make_constructor_fn(make_error, global, prototype, true, true) + make_constructor_fn(make_error, global, prototype, true) } /// Initialise the global object with the `Error` object. diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index 052d73d4d1a..715efec0973 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -14,7 +14,7 @@ use crate::{ builtins::{ array, - object::{Object, ObjectInternalMethods, ObjectKind, PROTOTYPE}, + object::{Object, ObjectInternalMethods, ObjectKind, INSTANCE_PROTOTYPE, PROTOTYPE}, property::Property, value::{ResultValue, Value}, }, @@ -109,14 +109,13 @@ pub struct Function { } impl Function { - /// This will create an ordinary function object - /// - /// - pub fn create_ordinary

( + pub fn new

( parameter_list: P, scope: Environment, body: FunctionBody, this_mode: ThisMode, + constructable: bool, + callable: bool, ) -> Self where P: Into>, @@ -127,11 +126,26 @@ impl Function { params: parameter_list.into(), kind: FunctionKind::Ordinary, this_mode, - constructable: true, - callable: true, + constructable, + callable, } } + /// This will create an ordinary function object + /// + /// + pub fn create_ordinary

( + parameter_list: P, + scope: Environment, + body: FunctionBody, + this_mode: ThisMode, + ) -> Self + where + P: Into>, + { + Self::new(parameter_list, scope, body, this_mode, true, true) + } + /// This will create a built-in function object /// /// @@ -215,7 +229,7 @@ impl Function { } } } else { - panic!("not callable"); + panic!("TypeError: class constructors must be invoked with 'new'"); } } @@ -283,7 +297,8 @@ impl Function { } } } else { - panic!("not constructable") + let name = this_obj.get_field_slice("name").to_string(); + panic!("TypeError: {} is not a constructor", name); } } @@ -328,6 +343,16 @@ impl Function { .borrow_mut() .initialize_binding(¶m.name, value); } + + /// Returns true if the function object is callable. + pub fn is_callable(&self) -> bool { + self.callable + } + + /// Returns true if the function object is constructable. + pub fn is_constructable(&self) -> bool { + self.constructable + } } impl Debug for Function { @@ -388,7 +413,7 @@ pub fn make_function(this: &mut Value, _: &[Value], _: &mut Interpreter) -> Resu pub fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); - make_constructor_fn(make_function, global, prototype, true, true) + make_constructor_fn(make_function, global, prototype, true) } /// Creates a new constructor function @@ -400,13 +425,11 @@ pub fn make_constructor_fn( global: &Value, proto: Value, constructable: bool, - callable: bool, ) -> Value { // Create the native function let mut constructor_fn = Function::create_builtin(Vec::new(), FunctionBody::BuiltIn(body)); constructor_fn.constructable = constructable; - constructor_fn.callable = callable; // Get reference to Function.prototype let func_prototype = global @@ -417,7 +440,7 @@ pub fn make_constructor_fn( let mut constructor_obj = Object::function(); constructor_obj.set_func(constructor_fn); - constructor_obj.set_internal_slot("__proto__", func_prototype); + constructor_obj.set_internal_slot(INSTANCE_PROTOTYPE, func_prototype); let constructor_val = Value::from(constructor_obj); // Set proto.constructor -> constructor_obj diff --git a/boa/src/builtins/number/mod.rs b/boa/src/builtins/number/mod.rs index 9d88908b861..7a61795c4d1 100644 --- a/boa/src/builtins/number/mod.rs +++ b/boa/src/builtins/number/mod.rs @@ -366,7 +366,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(to_string, named "toString", with length 1, of prototype); make_builtin_fn!(value_of, named "valueOf", of prototype); - make_constructor_fn(make_number, global, prototype, true, true) + make_constructor_fn(make_number, global, prototype, true) } /// Initialise the `Number` object on the global object. diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 31070ae412e..b62db9190b1 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -471,7 +471,10 @@ impl Object { /// /// [spec]: https://tc39.es/ecma262/#sec-iscallable pub fn is_callable(&self) -> bool { - self.func.is_some() + match self.func { + Some(ref function) => function.is_callable(), + None => false, + } } /// It determines if Object is a function object with a [[Construct]] internal method. @@ -480,8 +483,11 @@ impl Object { /// - [EcmaScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-isconstructor - pub fn is_constructor(&self) -> bool { - self.func.is_some() + pub fn is_constructable(&self) -> bool { + match self.func { + Some(ref function) => function.is_constructable(), + None => false, + } } } @@ -614,7 +620,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(has_own_property, named "hasOwnProperty", of prototype); make_builtin_fn!(to_string, named "toString", of prototype); - let object = make_constructor_fn(make_object, global, prototype, true, true); + let object = make_constructor_fn(make_object, global, prototype, true); object.set_field_slice("length", Value::from(1)); make_builtin_fn!(set_prototype_of, named "setPrototypeOf", with length 2, of object); diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index dcccd1f19d6..6eccbf68071 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -476,7 +476,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(get_sticky, named "sticky", of prototype); make_builtin_fn!(get_unicode, named "unicode", of prototype); - make_constructor_fn(make_regexp, global, prototype, true, true) + make_constructor_fn(make_regexp, global, prototype, true) } /// Initialise the `RegExp` object on the global object. diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index b93763b0a22..57c03002406 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -1021,7 +1021,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(match_all, named "matchAll", with length 1, of prototype); make_builtin_fn!(replace, named "replace", with length 2, of prototype); - make_constructor_fn(make_string, global, prototype, true, true) + make_constructor_fn(make_string, global, prototype, true) } /// Initialise the `String` object on the global object. diff --git a/boa/src/builtins/symbol/mod.rs b/boa/src/builtins/symbol/mod.rs index 86955277693..2b895cfe82d 100644 --- a/boa/src/builtins/symbol/mod.rs +++ b/boa/src/builtins/symbol/mod.rs @@ -94,7 +94,7 @@ pub fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); make_builtin_fn!(to_string, named "toString", of prototype); - make_constructor_fn(call_symbol, global, prototype, true, true) + make_constructor_fn(call_symbol, global, prototype, false) } /// Initialise the `Symbol` object on the global object. diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 77de6df642c..c55ebb1202e 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -217,7 +217,7 @@ impl ValueData { match *self { Self::Object(ref o) => { let borrowed_obj = o.borrow(); - borrowed_obj.is_callable() || borrowed_obj.is_constructor() + borrowed_obj.is_callable() || borrowed_obj.is_constructable() } _ => false, } diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index ebc7fba8f82..7b2e1c0b6d2 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -275,7 +275,8 @@ impl Executor for Interpreter { } // Node::FunctionDecl(ref name, ref args, ref expr) => { - let val = self.create_function(args.clone(), expr, ThisMode::NonLexical); + let val = + self.create_function(args.clone(), expr, ThisMode::NonLexical, true, true); // Set the name and assign it in the current environment val.set_field_slice("name", Value::from(name.clone())); @@ -291,7 +292,8 @@ impl Executor for Interpreter { } // Node::FunctionExpr(ref name, ref args, ref expr) => { - let val = self.create_function(args.clone(), expr, ThisMode::NonLexical); + let val = + self.create_function(args.clone(), expr, ThisMode::NonLexical, true, true); if let Some(name) = name { val.set_field_slice("name", Value::from(name.clone())); @@ -300,7 +302,7 @@ impl Executor for Interpreter { Ok(val) } Node::ArrowFunctionDecl(ref args, ref expr) => { - Ok(self.create_function(args.clone(), expr, ThisMode::Lexical)) + Ok(self.create_function(args.clone(), expr, ThisMode::Lexical, false, true)) } Node::BinOp(BinOp::Num(ref op), ref a, ref b) => { let v_a = self.run(a)?; @@ -589,6 +591,8 @@ impl Interpreter { args: Box<[FormalParameter]>, expr: &Node, this_mode: ThisMode, + constructable: bool, + callable: bool, ) -> Value { let function_prototype = &self .realm @@ -596,7 +600,7 @@ impl Interpreter { .get_global_object() .expect("Could not get the global object") .get_field_slice("Function") - .get_field_slice("Prototype"); + .get_field_slice(PROTOTYPE); // Every new function has a prototype property pre-made let global_val = &self @@ -606,11 +610,13 @@ impl Interpreter { .expect("Could not get the global object"); let proto = Value::new_object(Some(global_val)); - let func = FunctionObject::create_ordinary( + let func = FunctionObject::new( args.clone(), self.realm.environment.get_current_environment().clone(), FunctionBody::Ordinary(expr.clone()), this_mode, + constructable, + callable, ); let mut new_func = Object::function(); From 16808d071e274c45a0af3151674b415af5a2eafa Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Sat, 23 May 2020 12:47:57 +0200 Subject: [PATCH 3/5] Simplified Function object and removed FunctionKind --- boa/src/builtins/function/mod.rs | 89 ++++++++++++-------------------- boa/src/builtins/mod.rs | 2 +- boa/src/exec/mod.rs | 2 +- boa/src/realm.rs | 5 +- 4 files changed, 35 insertions(+), 63 deletions(-) diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index 715efec0973..728acd3843a 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -75,18 +75,6 @@ unsafe impl Trace for FunctionBody { unsafe_empty_trace!(); } -/// Signal what sort of function this is -#[derive(Clone, Debug, Copy, Finalize)] -pub enum FunctionKind { - BuiltIn, - Ordinary, -} - -/// Waiting on until we can derive Copy -unsafe impl Trace for FunctionKind { - unsafe_empty_trace!(); -} - /// Boa representation of a Function Object. /// /// @@ -98,8 +86,6 @@ pub struct Function { pub params: Box<[FormalParameter]>, /// This Mode pub this_mode: ThisMode, - /// Function kind - pub kind: FunctionKind, // Environment, built-in functions don't need Environments pub environment: Option, /// Is it constructable @@ -111,7 +97,7 @@ pub struct Function { impl Function { pub fn new

( parameter_list: P, - scope: Environment, + scope: Option, body: FunctionBody, this_mode: ThisMode, constructable: bool, @@ -122,9 +108,8 @@ impl Function { { Self { body, - environment: Some(scope), + environment: scope, params: parameter_list.into(), - kind: FunctionKind::Ordinary, this_mode, constructable, callable, @@ -137,31 +122,37 @@ impl Function { pub fn create_ordinary

( parameter_list: P, scope: Environment, - body: FunctionBody, + body: Node, this_mode: ThisMode, ) -> Self where P: Into>, { - Self::new(parameter_list, scope, body, this_mode, true, true) + Self::new( + parameter_list.into(), + Some(scope), + FunctionBody::Ordinary(body), + this_mode, + true, + true, + ) } /// This will create a built-in function object /// /// - pub fn create_builtin

(parameter_list: P, body: FunctionBody) -> Self + pub fn create_builtin

(parameter_list: P, body: NativeFunctionData) -> Self where P: Into>, { - Self { - body, - params: parameter_list.into(), - this_mode: ThisMode::NonLexical, - kind: FunctionKind::BuiltIn, - environment: None, - constructable: false, - callable: true, - } + Self::new( + parameter_list.into(), + None, + FunctionBody::BuiltIn(body), + ThisMode::NonLexical, + false, + true, + ) } /// This will handle calls for both ordinary and built-in functions @@ -176,14 +167,9 @@ impl Function { this_obj: &mut Value, ) -> ResultValue { if self.callable { - match self.kind { - FunctionKind::BuiltIn => match &self.body { - FunctionBody::BuiltIn(func) => func(this_obj, args_list, interpreter), - FunctionBody::Ordinary(_) => { - panic!("Builtin function should not have Ordinary Function body") - } - }, - FunctionKind::Ordinary => { + match self.body { + FunctionBody::BuiltIn(func) => func(this_obj, args_list, interpreter), + FunctionBody::Ordinary(ref body) => { // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment) // let local_env = new_function_environment( @@ -218,10 +204,7 @@ impl Function { interpreter.realm.environment.push(local_env); // Call body should be set before reaching here - let result = match &self.body { - FunctionBody::Ordinary(ref body) => interpreter.run(body), - _ => panic!("Ordinary function should not have BuiltIn Function body"), - }; + let result = interpreter.run(body); // local_env gets dropped here, its no longer needed interpreter.realm.environment.pop(); @@ -242,17 +225,12 @@ impl Function { this_obj: &mut Value, ) -> ResultValue { if self.constructable { - match self.kind { - FunctionKind::BuiltIn => match &self.body { - FunctionBody::BuiltIn(func) => { - func(this_obj, args_list, interpreter).unwrap(); - Ok(this_obj.clone()) - } - FunctionBody::Ordinary(_) => { - panic!("Builtin function should not have Ordinary Function body") - } - }, - FunctionKind::Ordinary => { + match self.body { + FunctionBody::BuiltIn(func) => { + func(this_obj, args_list, interpreter).unwrap(); + Ok(this_obj.clone()) + } + FunctionBody::Ordinary(ref body) => { // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment) // let local_env = new_function_environment( @@ -286,10 +264,7 @@ impl Function { interpreter.realm.environment.push(local_env); // Call body should be set before reaching here - let _ = match &self.body { - FunctionBody::Ordinary(ref body) => interpreter.run(body), - _ => panic!("Ordinary function should not have BuiltIn Function body"), - }; + let _ = interpreter.run(body); // local_env gets dropped here, its no longer needed let binding = interpreter.realm.environment.get_this_binding(); @@ -427,7 +402,7 @@ pub fn make_constructor_fn( constructable: bool, ) -> Value { // Create the native function - let mut constructor_fn = Function::create_builtin(Vec::new(), FunctionBody::BuiltIn(body)); + let mut constructor_fn = Function::create_builtin(Vec::new(), body); constructor_fn.constructable = constructable; diff --git a/boa/src/builtins/mod.rs b/boa/src/builtins/mod.rs index 912c5000e7c..c08b397a211 100644 --- a/boa/src/builtins/mod.rs +++ b/boa/src/builtins/mod.rs @@ -7,7 +7,7 @@ macro_rules! make_builtin_fn { ($fn:ident, named $name:expr, with length $l:tt, of $p:ident) => { let func = crate::builtins::function::Function::create_builtin( vec![], - crate::builtins::function::FunctionBody::BuiltIn($fn), + $fn, ); let mut new_func = crate::builtins::object::Object::function(); diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 7b2e1c0b6d2..c9a1eb279d6 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -612,7 +612,7 @@ impl Interpreter { let func = FunctionObject::new( args.clone(), - self.realm.environment.get_current_environment().clone(), + Some(self.realm.environment.get_current_environment().clone()), FunctionBody::Ordinary(expr.clone()), this_mode, constructable, diff --git a/boa/src/realm.rs b/boa/src/realm.rs index ba044f46451..6f0bb33cd99 100644 --- a/boa/src/realm.rs +++ b/boa/src/realm.rs @@ -60,10 +60,7 @@ impl Realm { /// Utility to add a function to the global object pub fn register_global_func(self, func_name: &str, func: NativeFunctionData) -> Self { - let func = crate::builtins::function::Function::create_builtin( - vec![], - crate::builtins::function::FunctionBody::BuiltIn(func), - ); + let func = crate::builtins::function::Function::create_builtin(Vec::new(), func); self.global_obj .set_field(Value::from(func_name), ValueData::from_func(func)); From d01d61a02ca3bed580150491083a1add188ac35b Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Sat, 23 May 2020 13:02:49 +0200 Subject: [PATCH 4/5] Rnamed create_ordinary -> ordinary, create_builtin -> builtin --- boa/src/builtins/function/mod.rs | 6 +++--- boa/src/builtins/mod.rs | 6 +++--- boa/src/realm.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index 728acd3843a..953b5c4b112 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -119,7 +119,7 @@ impl Function { /// This will create an ordinary function object /// /// - pub fn create_ordinary

( + pub fn ordinary

( parameter_list: P, scope: Environment, body: Node, @@ -141,7 +141,7 @@ impl Function { /// This will create a built-in function object /// /// - pub fn create_builtin

(parameter_list: P, body: NativeFunctionData) -> Self + pub fn builtin

(parameter_list: P, body: NativeFunctionData) -> Self where P: Into>, { @@ -402,7 +402,7 @@ pub fn make_constructor_fn( constructable: bool, ) -> Value { // Create the native function - let mut constructor_fn = Function::create_builtin(Vec::new(), body); + let mut constructor_fn = Function::builtin(Vec::new(), body); constructor_fn.constructable = constructable; diff --git a/boa/src/builtins/mod.rs b/boa/src/builtins/mod.rs index c08b397a211..3292cb2ec0d 100644 --- a/boa/src/builtins/mod.rs +++ b/boa/src/builtins/mod.rs @@ -1,12 +1,12 @@ -//! Builtins live here, such as Object, String, Math etc +//! Builtins live here, such as Object, String, Math, etc. /// Macro to create a new member function of a prototype. /// /// If no length is provided, the length will be set to 0. macro_rules! make_builtin_fn { ($fn:ident, named $name:expr, with length $l:tt, of $p:ident) => { - let func = crate::builtins::function::Function::create_builtin( - vec![], + let func = crate::builtins::function::Function::builtin( + Vec::new(), $fn, ); diff --git a/boa/src/realm.rs b/boa/src/realm.rs index 6f0bb33cd99..44c9ac952ac 100644 --- a/boa/src/realm.rs +++ b/boa/src/realm.rs @@ -7,7 +7,7 @@ use crate::{ builtins::{ self, - function::NativeFunctionData, + function::{Function, NativeFunctionData}, value::{Value, ValueData}, }, environment::{ @@ -60,7 +60,7 @@ impl Realm { /// Utility to add a function to the global object pub fn register_global_func(self, func_name: &str, func: NativeFunctionData) -> Self { - let func = crate::builtins::function::Function::create_builtin(Vec::new(), func); + let func = Function::builtin(Vec::new(), func); self.global_obj .set_field(Value::from(func_name), ValueData::from_func(func)); From 70f2ef47f6cf5ba39ec9d2dfcb57dd4db76cdc64 Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Sat, 23 May 2020 15:32:36 +0200 Subject: [PATCH 5/5] Fixed name and length properties in global objects --- boa/src/builtins/array/mod.rs | 2 +- boa/src/builtins/bigint/mod.rs | 2 +- boa/src/builtins/boolean/mod.rs | 2 +- boa/src/builtins/error.rs | 2 +- boa/src/builtins/function/mod.rs | 30 ++++++++++++++++++------------ boa/src/builtins/number/mod.rs | 2 +- boa/src/builtins/object/mod.rs | 2 +- boa/src/builtins/regexp/mod.rs | 2 +- boa/src/builtins/string/mod.rs | 2 +- boa/src/builtins/symbol/mod.rs | 2 +- 10 files changed, 27 insertions(+), 21 deletions(-) diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 9b614e20498..7f27b3ed0f1 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -978,7 +978,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(slice, named "slice", with length 2, of prototype); make_builtin_fn!(some, named "some", with length 2, of prototype); - let array = make_constructor_fn(make_array, global, prototype, true); + let array = make_constructor_fn("Array", 1, make_array, global, prototype, true); // Static Methods make_builtin_fn!(is_array, named "isArray", with length 1, of array); diff --git a/boa/src/builtins/bigint/mod.rs b/boa/src/builtins/bigint/mod.rs index 192d65dabe5..a53b1152133 100644 --- a/boa/src/builtins/bigint/mod.rs +++ b/boa/src/builtins/bigint/mod.rs @@ -96,7 +96,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(to_string, named "toString", with length 1, of prototype); make_builtin_fn!(value_of, named "valueOf", of prototype); - make_constructor_fn(make_bigint, global, prototype, false) + make_constructor_fn("BigInt", 1, make_bigint, global, prototype, false) } /// Initialise the `BigInt` object on the global object. diff --git a/boa/src/builtins/boolean/mod.rs b/boa/src/builtins/boolean/mod.rs index 7351423d199..f119de15ea0 100644 --- a/boa/src/builtins/boolean/mod.rs +++ b/boa/src/builtins/boolean/mod.rs @@ -104,7 +104,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(to_string, named "toString", of prototype); make_builtin_fn!(value_of, named "valueOf", of prototype); - make_constructor_fn(construct_boolean, global, prototype, true) + make_constructor_fn("Boolean", 1, construct_boolean, global, prototype, true) } /// Initialise the `Boolean` object on the global object. diff --git a/boa/src/builtins/error.rs b/boa/src/builtins/error.rs index c003c789d13..3261fa0ae73 100644 --- a/boa/src/builtins/error.rs +++ b/boa/src/builtins/error.rs @@ -60,7 +60,7 @@ pub fn create(global: &Value) -> Value { prototype.set_field_slice("name", Value::from("Error")); make_builtin_fn!(to_string, named "toString", of prototype); - make_constructor_fn(make_error, global, prototype, true) + make_constructor_fn("Error", 1, make_error, global, prototype, true) } /// Initialise the global object with the `Error` object. diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index 953b5c4b112..a6d3b0d835c 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -272,7 +272,7 @@ impl Function { } } } else { - let name = this_obj.get_field_slice("name").to_string(); + let name = this.get_field_slice("name").to_string(); panic!("TypeError: {} is not a constructor", name); } } @@ -338,16 +338,6 @@ impl Debug for Function { } } -/// Function Prototype. -/// -/// -pub fn create_function_prototype() { - let mut function_prototype: Object = Object::default(); - // Set Kind to function (for historical & compatibility reasons) - // - function_prototype.kind = ObjectKind::Function; -} - /// Arguments. /// /// @@ -388,7 +378,7 @@ pub fn make_function(this: &mut Value, _: &[Value], _: &mut Interpreter) -> Resu pub fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); - make_constructor_fn(make_function, global, prototype, true) + make_constructor_fn("Function", 1, make_function, global, prototype, true) } /// Creates a new constructor function @@ -396,6 +386,8 @@ pub fn create(global: &Value) -> Value { /// This utility function handling linking the new Constructor to the prototype. /// So far this is only used by internal functions pub fn make_constructor_fn( + name: &str, + length: i32, body: NativeFunctionData, global: &Value, proto: Value, @@ -422,6 +414,20 @@ pub fn make_constructor_fn( proto.set_field_slice("constructor", constructor_val.clone()); constructor_val.set_field_slice(PROTOTYPE, proto); + let length = Property::new() + .value(Value::from(length)) + .writable(false) + .configurable(false) + .enumerable(false); + constructor_val.set_property_slice("length", length); + + let name = Property::new() + .value(Value::from(name)) + .writable(false) + .configurable(false) + .enumerable(false); + constructor_val.set_property_slice("name", name); + constructor_val } diff --git a/boa/src/builtins/number/mod.rs b/boa/src/builtins/number/mod.rs index 7a61795c4d1..4b6a78224a3 100644 --- a/boa/src/builtins/number/mod.rs +++ b/boa/src/builtins/number/mod.rs @@ -366,7 +366,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(to_string, named "toString", with length 1, of prototype); make_builtin_fn!(value_of, named "valueOf", of prototype); - make_constructor_fn(make_number, global, prototype, true) + make_constructor_fn("Number", 1, make_number, global, prototype, true) } /// Initialise the `Number` object on the global object. diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index b62db9190b1..099cf2368ba 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -620,7 +620,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(has_own_property, named "hasOwnProperty", of prototype); make_builtin_fn!(to_string, named "toString", of prototype); - let object = make_constructor_fn(make_object, global, prototype, true); + let object = make_constructor_fn("Object", 1, make_object, global, prototype, true); object.set_field_slice("length", Value::from(1)); make_builtin_fn!(set_prototype_of, named "setPrototypeOf", with length 2, of object); diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index 6eccbf68071..c03baf07133 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -476,7 +476,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(get_sticky, named "sticky", of prototype); make_builtin_fn!(get_unicode, named "unicode", of prototype); - make_constructor_fn(make_regexp, global, prototype, true) + make_constructor_fn("RegExp", 1, make_regexp, global, prototype, true) } /// Initialise the `RegExp` object on the global object. diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index 57c03002406..120c9bdde62 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -1021,7 +1021,7 @@ pub fn create(global: &Value) -> Value { make_builtin_fn!(match_all, named "matchAll", with length 1, of prototype); make_builtin_fn!(replace, named "replace", with length 2, of prototype); - make_constructor_fn(make_string, global, prototype, true) + make_constructor_fn("String", 1, make_string, global, prototype, true) } /// Initialise the `String` object on the global object. diff --git a/boa/src/builtins/symbol/mod.rs b/boa/src/builtins/symbol/mod.rs index 2b895cfe82d..6613c4b3bb3 100644 --- a/boa/src/builtins/symbol/mod.rs +++ b/boa/src/builtins/symbol/mod.rs @@ -94,7 +94,7 @@ pub fn create(global: &Value) -> Value { let prototype = Value::new_object(Some(global)); make_builtin_fn!(to_string, named "toString", of prototype); - make_constructor_fn(call_symbol, global, prototype, false) + make_constructor_fn("Symbol", 1, call_symbol, global, prototype, false) } /// Initialise the `Symbol` object on the global object.