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
/// [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> {
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<Value> {
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"),

16
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<Value> {
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))

2
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()))
}

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

@ -9,7 +9,7 @@ impl Executable for GetConstField {
fn run(&self, interpreter: &mut Context) -> Result<Value> {
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<Value> {
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)?;

9
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(_))

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
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: <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 {
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()),
}
}

Loading…
Cancel
Save