Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Value::to_object to return GcObject #712

Merged
merged 2 commits into from
Sep 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions boa/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down Expand Up @@ -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"),
Expand Down
16 changes: 7 additions & 9 deletions boa/src/builtins/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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();
Expand All @@ -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()
Expand Down Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion boa/src/exec/call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
}
Expand Down
4 changes: 2 additions & 2 deletions boa/src/exec/field/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
Expand All @@ -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)?;

Expand Down
9 changes: 9 additions & 0 deletions boa/src/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_))
Expand Down
46 changes: 20 additions & 26 deletions boa/src/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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(
Expand Down Expand Up @@ -668,15 +660,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
Expand All @@ -686,10 +678,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
Expand All @@ -698,10 +690,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
Expand All @@ -711,10 +703,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
Expand All @@ -724,10 +716,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
Expand All @@ -737,10 +729,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
Expand All @@ -749,11 +741,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()),
}
}

Expand Down