From 0348ba9323b1292a1ad7e95466b7c10a8ffa6cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Borges?= Date: Sun, 27 Sep 2020 18:04:07 +0100 Subject: [PATCH] Refactor: Value::to_object to return GcObject (#712) --- boa/src/builtins/array/mod.rs | 4 +-- boa/src/builtins/object/mod.rs | 16 ++++++------ boa/src/exec/call/mod.rs | 2 +- boa/src/exec/field/mod.rs | 4 +-- boa/src/object/mod.rs | 9 +++++++ boa/src/value/mod.rs | 46 +++++++++++++++------------------- 6 files changed, 41 insertions(+), 40 deletions(-) diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index c9fe1bacab..f90f3dbea6 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -960,7 +960,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], interpreter: &mut Context) -> Result { - let this = this.to_object(interpreter)?; + let this: Value = this.to_object(interpreter)?.into(); let callback = match args.get(0) { Some(value) if value.is_function() => value, _ => return interpreter.throw_type_error("Reduce was called without a callback"), @@ -1022,7 +1022,7 @@ impl Array { args: &[Value], interpreter: &mut Context, ) -> Result { - let this = this.to_object(interpreter)?; + let this: Value = this.to_object(interpreter)?.into(); let callback = match args.get(0) { Some(value) if value.is_function() => value, _ => return interpreter.throw_type_error("reduceRight was called without a callback"), diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 3bd9093a21..7e488e1b26 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -15,7 +15,7 @@ use crate::{ builtins::function::{make_builtin_fn, make_constructor_fn}, - object::ObjectData, + object::{Object as BuiltinObject, ObjectData}, property::Property, value::{same_value, Value}, BoaProfiler, Context, Result, @@ -33,7 +33,7 @@ impl Object { pub fn make_object(_: &Value, args: &[Value], ctx: &mut Context) -> Result { if let Some(arg) = args.get(0) { if !arg.is_null_or_undefined() { - return arg.to_object(ctx); + return Ok(arg.to_object(ctx)?.into()); } } let global = ctx.global_object(); @@ -60,10 +60,10 @@ impl Object { } match prototype { - Value::Object(_) | Value::Null => Ok(Value::new_object_from_prototype( + Value::Object(_) | Value::Null => Ok(Value::object(BuiltinObject::with_prototype( prototype, ObjectData::Ordinary, - )), + ))), _ => interpreter.throw_type_error(format!( "Object prototype may only be an Object or null: {}", prototype.display() @@ -160,11 +160,9 @@ impl Object { }; let key = key.to_property_key(ctx)?; - let own_property = this.to_object(ctx).map(|obj| { - obj.as_object() - .expect("Unable to deref object") - .get_own_property(&key) - }); + let own_property = this + .to_object(ctx) + .map(|obj| obj.borrow().get_own_property(&key)); Ok(own_property.map_or(Value::from(false), |own_prop| { Value::from(own_prop.enumerable_or(false)) diff --git a/boa/src/exec/call/mod.rs b/boa/src/exec/call/mod.rs index c0b6666561..dcf86bee73 100644 --- a/boa/src/exec/call/mod.rs +++ b/boa/src/exec/call/mod.rs @@ -12,7 +12,7 @@ impl Executable for Call { Node::GetConstField(ref get_const_field) => { let mut obj = get_const_field.obj().run(interpreter)?; if obj.get_type() != Type::Object { - obj = obj.to_object(interpreter)?; + obj = Value::Object(obj.to_object(interpreter)?); } (obj.clone(), obj.get_field(get_const_field.field())) } diff --git a/boa/src/exec/field/mod.rs b/boa/src/exec/field/mod.rs index 5cc0b156f5..dfa9f4d840 100644 --- a/boa/src/exec/field/mod.rs +++ b/boa/src/exec/field/mod.rs @@ -9,7 +9,7 @@ impl Executable for GetConstField { fn run(&self, interpreter: &mut Context) -> Result { let mut obj = self.obj().run(interpreter)?; if obj.get_type() != Type::Object { - obj = obj.to_object(interpreter)?; + obj = Value::Object(obj.to_object(interpreter)?); } Ok(obj.get_field(self.field())) @@ -20,7 +20,7 @@ impl Executable for GetField { fn run(&self, interpreter: &mut Context) -> Result { let mut obj = self.obj().run(interpreter)?; if obj.get_type() != Type::Object { - obj = obj.to_object(interpreter)?; + obj = Value::Object(obj.to_object(interpreter)?); } let field = self.field().run(interpreter)?; diff --git a/boa/src/object/mod.rs b/boa/src/object/mod.rs index 667a65ed37..fe92ddc76c 100644 --- a/boa/src/object/mod.rs +++ b/boa/src/object/mod.rs @@ -401,6 +401,15 @@ impl Object { self.prototype = prototype } + /// Similar to `Value::new_object`, but you can pass a prototype to create from, plus a kind + #[inline] + pub fn with_prototype(proto: Value, data: ObjectData) -> Object { + let mut object = Object::default(); + object.data = data; + object.set_prototype_instance(proto); + object + } + /// Returns `true` if it holds an Rust type that implements `NativeObject`. pub fn is_native_object(&self) -> bool { matches!(self.data, ObjectData::NativeObject(_)) diff --git a/boa/src/value/mod.rs b/boa/src/value/mod.rs index c3149da12c..93826e5322 100644 --- a/boa/src/value/mod.rs +++ b/boa/src/value/mod.rs @@ -164,14 +164,6 @@ impl Value { } } - /// Similar to `new_object`, but you can pass a prototype to create from, plus a kind - pub fn new_object_from_prototype(proto: Value, data: ObjectData) -> Self { - let mut object = Object::default(); - object.data = data; - object.set_prototype_instance(proto); - Self::object(object) - } - /// Convert from a JSON value to a JS value pub fn from_json(json: JSONValue, interpreter: &mut Context) -> Self { match json { @@ -189,8 +181,8 @@ impl Value { .global_object() .get_field("Array") .get_field(PROTOTYPE); - let new_obj = - Value::new_object_from_prototype(global_array_prototype, ObjectData::Array); + let new_obj_obj = Object::with_prototype(global_array_prototype, ObjectData::Array); + let new_obj = Value::object(new_obj_obj); let length = vs.len(); for (idx, json) in vs.into_iter().enumerate() { new_obj.set_property( @@ -665,15 +657,15 @@ impl Value { } } - /// Converts th value to a value of type Object. + /// Converts the value to an Object. /// /// This function is equivalent to `Object(value)` in JavaScript /// /// See: - pub fn to_object(&self, ctx: &mut Context) -> Result { + pub fn to_object(&self, ctx: &mut Context) -> Result { match self { Value::Undefined | Value::Null => { - ctx.throw_type_error("cannot convert 'null' or 'undefined' to object") + Err(ctx.construct_type_error("cannot convert 'null' or 'undefined' to object")) } Value::Boolean(boolean) => { let proto = ctx @@ -683,10 +675,10 @@ impl Value { .expect("Boolean was not initialized") .get_field(PROTOTYPE); - Ok(Value::new_object_from_prototype( + Ok(GcObject::new(Object::with_prototype( proto, ObjectData::Boolean(*boolean), - )) + ))) } Value::Integer(integer) => { let proto = ctx @@ -695,10 +687,10 @@ impl Value { .get_binding_value("Number") .expect("Number was not initialized") .get_field(PROTOTYPE); - Ok(Value::new_object_from_prototype( + Ok(GcObject::new(Object::with_prototype( proto, ObjectData::Number(f64::from(*integer)), - )) + ))) } Value::Rational(rational) => { let proto = ctx @@ -708,10 +700,10 @@ impl Value { .expect("Number was not initialized") .get_field(PROTOTYPE); - Ok(Value::new_object_from_prototype( + Ok(GcObject::new(Object::with_prototype( proto, ObjectData::Number(*rational), - )) + ))) } Value::String(ref string) => { let proto = ctx @@ -721,10 +713,10 @@ impl Value { .expect("String was not initialized") .get_field(PROTOTYPE); - Ok(Value::new_object_from_prototype( + Ok(GcObject::new(Object::with_prototype( proto, ObjectData::String(string.clone()), - )) + ))) } Value::Symbol(ref symbol) => { let proto = ctx @@ -734,10 +726,10 @@ impl Value { .expect("Symbol was not initialized") .get_field(PROTOTYPE); - Ok(Value::new_object_from_prototype( + Ok(GcObject::new(Object::with_prototype( proto, ObjectData::Symbol(symbol.clone()), - )) + ))) } Value::BigInt(ref bigint) => { let proto = ctx @@ -746,11 +738,13 @@ impl Value { .get_binding_value("BigInt") .expect("BigInt was not initialized") .get_field(PROTOTYPE); - let bigint_obj = - Value::new_object_from_prototype(proto, ObjectData::BigInt(bigint.clone())); + let bigint_obj = GcObject::new(Object::with_prototype( + proto, + ObjectData::BigInt(bigint.clone()), + )); Ok(bigint_obj) } - Value::Object(_) => Ok(self.clone()), + Value::Object(gcobject) => Ok(gcobject.clone()), } }