Browse Source

Refactor: Value::to_object to return GcObject (#712)

pull/723/head
João Borges 4 years ago committed by GitHub
parent
commit
0348ba9323
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      boa/src/builtins/array/mod.rs
  2. 16
      boa/src/builtins/object/mod.rs
  3. 2
      boa/src/exec/call/mod.rs
  4. 4
      boa/src/exec/field/mod.rs
  5. 9
      boa/src/object/mod.rs
  6. 46
      boa/src/value/mod.rs

4
boa/src/builtins/array/mod.rs

@ -960,7 +960,7 @@ impl Array {
/// [spec]: https://tc39.es/ecma262/#sec-array.prototype.reduce /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.reduce
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/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<Value> { pub(crate) fn reduce(this: &Value, args: &[Value], interpreter: &mut Context) -> Result<Value> {
let this = this.to_object(interpreter)?; let this: Value = this.to_object(interpreter)?.into();
let callback = match args.get(0) { let callback = match args.get(0) {
Some(value) if value.is_function() => value, Some(value) if value.is_function() => value,
_ => return interpreter.throw_type_error("Reduce was called without a callback"), _ => return interpreter.throw_type_error("Reduce was called without a callback"),
@ -1022,7 +1022,7 @@ impl Array {
args: &[Value], args: &[Value],
interpreter: &mut Context, interpreter: &mut Context,
) -> Result<Value> { ) -> Result<Value> {
let this = this.to_object(interpreter)?; let this: Value = this.to_object(interpreter)?.into();
let callback = match args.get(0) { let callback = match args.get(0) {
Some(value) if value.is_function() => value, Some(value) if value.is_function() => value,
_ => return interpreter.throw_type_error("reduceRight was called without a callback"), _ => return interpreter.throw_type_error("reduceRight was called without a callback"),

16
boa/src/builtins/object/mod.rs

@ -15,7 +15,7 @@
use crate::{ use crate::{
builtins::function::{make_builtin_fn, make_constructor_fn}, builtins::function::{make_builtin_fn, make_constructor_fn},
object::ObjectData, object::{Object as BuiltinObject, ObjectData},
property::Property, property::Property,
value::{same_value, Value}, value::{same_value, Value},
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
@ -33,7 +33,7 @@ impl Object {
pub fn make_object(_: &Value, args: &[Value], ctx: &mut Context) -> Result<Value> { pub fn make_object(_: &Value, args: &[Value], ctx: &mut Context) -> Result<Value> {
if let Some(arg) = args.get(0) { if let Some(arg) = args.get(0) {
if !arg.is_null_or_undefined() { if !arg.is_null_or_undefined() {
return arg.to_object(ctx); return Ok(arg.to_object(ctx)?.into());
} }
} }
let global = ctx.global_object(); let global = ctx.global_object();
@ -60,10 +60,10 @@ impl Object {
} }
match prototype { match prototype {
Value::Object(_) | Value::Null => Ok(Value::new_object_from_prototype( Value::Object(_) | Value::Null => Ok(Value::object(BuiltinObject::with_prototype(
prototype, prototype,
ObjectData::Ordinary, ObjectData::Ordinary,
)), ))),
_ => interpreter.throw_type_error(format!( _ => interpreter.throw_type_error(format!(
"Object prototype may only be an Object or null: {}", "Object prototype may only be an Object or null: {}",
prototype.display() prototype.display()
@ -160,11 +160,9 @@ impl Object {
}; };
let key = key.to_property_key(ctx)?; let key = key.to_property_key(ctx)?;
let own_property = this.to_object(ctx).map(|obj| { let own_property = this
obj.as_object() .to_object(ctx)
.expect("Unable to deref object") .map(|obj| obj.borrow().get_own_property(&key));
.get_own_property(&key)
});
Ok(own_property.map_or(Value::from(false), |own_prop| { Ok(own_property.map_or(Value::from(false), |own_prop| {
Value::from(own_prop.enumerable_or(false)) Value::from(own_prop.enumerable_or(false))

2
boa/src/exec/call/mod.rs

@ -12,7 +12,7 @@ impl Executable for Call {
Node::GetConstField(ref get_const_field) => { Node::GetConstField(ref get_const_field) => {
let mut obj = get_const_field.obj().run(interpreter)?; let mut obj = get_const_field.obj().run(interpreter)?;
if obj.get_type() != Type::Object { 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())) (obj.clone(), obj.get_field(get_const_field.field()))
} }

4
boa/src/exec/field/mod.rs

@ -9,7 +9,7 @@ impl Executable for GetConstField {
fn run(&self, interpreter: &mut Context) -> Result<Value> { fn run(&self, interpreter: &mut Context) -> Result<Value> {
let mut obj = self.obj().run(interpreter)?; let mut obj = self.obj().run(interpreter)?;
if obj.get_type() != Type::Object { if obj.get_type() != Type::Object {
obj = obj.to_object(interpreter)?; obj = Value::Object(obj.to_object(interpreter)?);
} }
Ok(obj.get_field(self.field())) Ok(obj.get_field(self.field()))
@ -20,7 +20,7 @@ impl Executable for GetField {
fn run(&self, interpreter: &mut Context) -> Result<Value> { fn run(&self, interpreter: &mut Context) -> Result<Value> {
let mut obj = self.obj().run(interpreter)?; let mut obj = self.obj().run(interpreter)?;
if obj.get_type() != Type::Object { if obj.get_type() != Type::Object {
obj = obj.to_object(interpreter)?; obj = Value::Object(obj.to_object(interpreter)?);
} }
let field = self.field().run(interpreter)?; let field = self.field().run(interpreter)?;

9
boa/src/object/mod.rs

@ -401,6 +401,15 @@ impl Object {
self.prototype = prototype 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`. /// Returns `true` if it holds an Rust type that implements `NativeObject`.
pub fn is_native_object(&self) -> bool { pub fn is_native_object(&self) -> bool {
matches!(self.data, ObjectData::NativeObject(_)) matches!(self.data, ObjectData::NativeObject(_))

46
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 /// Convert from a JSON value to a JS value
pub fn from_json(json: JSONValue, interpreter: &mut Context) -> Self { pub fn from_json(json: JSONValue, interpreter: &mut Context) -> Self {
match json { match json {
@ -189,8 +181,8 @@ impl Value {
.global_object() .global_object()
.get_field("Array") .get_field("Array")
.get_field(PROTOTYPE); .get_field(PROTOTYPE);
let new_obj = let new_obj_obj = Object::with_prototype(global_array_prototype, ObjectData::Array);
Value::new_object_from_prototype(global_array_prototype, ObjectData::Array); let new_obj = Value::object(new_obj_obj);
let length = vs.len(); let length = vs.len();
for (idx, json) in vs.into_iter().enumerate() { for (idx, json) in vs.into_iter().enumerate() {
new_obj.set_property( 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 /// This function is equivalent to `Object(value)` in JavaScript
/// ///
/// See: <https://tc39.es/ecma262/#sec-toobject> /// See: <https://tc39.es/ecma262/#sec-toobject>
pub fn to_object(&self, ctx: &mut Context) -> Result<Value> { pub fn to_object(&self, ctx: &mut Context) -> Result<GcObject> {
match self { match self {
Value::Undefined | Value::Null => { 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) => { Value::Boolean(boolean) => {
let proto = ctx let proto = ctx
@ -683,10 +675,10 @@ impl Value {
.expect("Boolean was not initialized") .expect("Boolean was not initialized")
.get_field(PROTOTYPE); .get_field(PROTOTYPE);
Ok(Value::new_object_from_prototype( Ok(GcObject::new(Object::with_prototype(
proto, proto,
ObjectData::Boolean(*boolean), ObjectData::Boolean(*boolean),
)) )))
} }
Value::Integer(integer) => { Value::Integer(integer) => {
let proto = ctx let proto = ctx
@ -695,10 +687,10 @@ impl Value {
.get_binding_value("Number") .get_binding_value("Number")
.expect("Number was not initialized") .expect("Number was not initialized")
.get_field(PROTOTYPE); .get_field(PROTOTYPE);
Ok(Value::new_object_from_prototype( Ok(GcObject::new(Object::with_prototype(
proto, proto,
ObjectData::Number(f64::from(*integer)), ObjectData::Number(f64::from(*integer)),
)) )))
} }
Value::Rational(rational) => { Value::Rational(rational) => {
let proto = ctx let proto = ctx
@ -708,10 +700,10 @@ impl Value {
.expect("Number was not initialized") .expect("Number was not initialized")
.get_field(PROTOTYPE); .get_field(PROTOTYPE);
Ok(Value::new_object_from_prototype( Ok(GcObject::new(Object::with_prototype(
proto, proto,
ObjectData::Number(*rational), ObjectData::Number(*rational),
)) )))
} }
Value::String(ref string) => { Value::String(ref string) => {
let proto = ctx let proto = ctx
@ -721,10 +713,10 @@ impl Value {
.expect("String was not initialized") .expect("String was not initialized")
.get_field(PROTOTYPE); .get_field(PROTOTYPE);
Ok(Value::new_object_from_prototype( Ok(GcObject::new(Object::with_prototype(
proto, proto,
ObjectData::String(string.clone()), ObjectData::String(string.clone()),
)) )))
} }
Value::Symbol(ref symbol) => { Value::Symbol(ref symbol) => {
let proto = ctx let proto = ctx
@ -734,10 +726,10 @@ impl Value {
.expect("Symbol was not initialized") .expect("Symbol was not initialized")
.get_field(PROTOTYPE); .get_field(PROTOTYPE);
Ok(Value::new_object_from_prototype( Ok(GcObject::new(Object::with_prototype(
proto, proto,
ObjectData::Symbol(symbol.clone()), ObjectData::Symbol(symbol.clone()),
)) )))
} }
Value::BigInt(ref bigint) => { Value::BigInt(ref bigint) => {
let proto = ctx let proto = ctx
@ -746,11 +738,13 @@ impl Value {
.get_binding_value("BigInt") .get_binding_value("BigInt")
.expect("BigInt was not initialized") .expect("BigInt was not initialized")
.get_field(PROTOTYPE); .get_field(PROTOTYPE);
let bigint_obj = let bigint_obj = GcObject::new(Object::with_prototype(
Value::new_object_from_prototype(proto, ObjectData::BigInt(bigint.clone())); proto,
ObjectData::BigInt(bigint.clone()),
));
Ok(bigint_obj) Ok(bigint_obj)
} }
Value::Object(_) => Ok(self.clone()), Value::Object(gcobject) => Ok(gcobject.clone()),
} }
} }

Loading…
Cancel
Save