Skip to content
73 changes: 1 addition & 72 deletions core/engine/src/object/jsobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

use super::{
JsPrototype, NativeObject, Object, ObjectData, PrivateName, PropertyMap,
internal_methods::{
InternalMethodPropertyContext, InternalObjectMethods, ORDINARY_INTERNAL_METHODS,
},
internal_methods::{InternalObjectMethods, ORDINARY_INTERNAL_METHODS},
shape::RootShape,
};
use crate::{
Expand Down Expand Up @@ -768,75 +766,6 @@ Cannot both specify accessors and a value or writable attribute",
Ok(desc.build())
}

/// `7.3.25 CopyDataProperties ( target, source, excludedItems )`
///
/// More information:
/// - [ECMAScript][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-copydataproperties
pub fn copy_data_properties<K>(
&self,
source: &JsValue,
excluded_keys: Vec<K>,
context: &mut Context,
) -> JsResult<()>
where
K: Into<PropertyKey>,
{
let context = &mut InternalMethodPropertyContext::new(context);

// 1. Assert: Type(target) is Object.
// 2. Assert: excludedItems is a List of property keys.
// 3. If source is undefined or null, return target.
if source.is_null_or_undefined() {
return Ok(());
}

// 4. Let from be ! ToObject(source).
let from = source
.to_object(context)
.expect("function ToObject should never complete abruptly here");

// 5. Let keys be ? from.[[OwnPropertyKeys]]().
// 6. For each element nextKey of keys, do
let excluded_keys: Vec<PropertyKey> = excluded_keys.into_iter().map(Into::into).collect();
for key in from.__own_property_keys__(context)? {
// a. Let excluded be false.
let mut excluded = false;

// b. For each element e of excludedItems, do
for e in &excluded_keys {
// i. If SameValue(e, nextKey) is true, then
if *e == key {
// 1. Set excluded to true.
excluded = true;
break;
}
}
// c. If excluded is false, then
if !excluded {
// i. Let desc be ? from.[[GetOwnProperty]](nextKey).
let desc = from.__get_own_property__(&key, context)?;

// ii. If desc is not undefined and desc.[[Enumerable]] is true, then
if let Some(desc) = desc
&& let Some(enumerable) = desc.enumerable()
&& enumerable
{
// 1. Let propValue be ? Get(from, nextKey).
let prop_value = from.__get__(&key, from.clone().into(), context)?;

// 2. Perform ! CreateDataPropertyOrThrow(target, nextKey, propValue).
self.create_data_property_or_throw(key, prop_value, context)
.expect("CreateDataPropertyOrThrow should never complete abruptly here");
}
}
}

// 7. Return target.
Ok(())
}

// Allow lint, false positive.
#[allow(clippy::assigning_clones)]
pub(crate) fn get_property(&self, key: &PropertyKey) -> Option<PropertyDescriptor> {
Expand Down
105 changes: 103 additions & 2 deletions core/engine/src/object/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,41 @@ impl JsObject {
self.__define_own_property__(&key.into(), new_desc.into(), context)
}

// todo: CreateMethodProperty
/// `10.2.8 DefineMethodProperty ( homeObject, key, closure, enumerable )`
///
/// Defines a method property on an object with the specified attributes.
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-definemethodproperty
pub(crate) fn define_method_property<K, V>(
&self,
key: K,
value: V,
context: &mut InternalMethodPropertyContext<'_>,
) -> JsResult<()>
where
K: Into<PropertyKey>,
V: Into<JsValue>,
{
// 1. Assert: homeObject is an ordinary, extensible object with no non-configurable properties.
// 2. If key is a Private Name, then
// a. Return PrivateElement { [[Key]]: key, [[Kind]]: method, [[Value]]: closure }.
// 3. Else,
// a. Let desc be the PropertyDescriptor { [[Value]]: closure, [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true }.
let new_desc = PropertyDescriptor::builder()
.value(value)
.writable(true)
.enumerable(false)
.configurable(true);

// b. Perform ! DefinePropertyOrThrow(homeObject, key, desc).
self.__define_own_property__(&key.into(), new_desc.into(), context)?;

// c. Return unused.
Ok(())
}

/// Create data property or throw
///
Expand Down Expand Up @@ -842,7 +876,74 @@ impl JsObject {
Ok(context.realm().clone())
}

// todo: CopyDataProperties
/// `7.3.26 CopyDataProperties ( target, source, excludedItems )`
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-copydataproperties
pub fn copy_data_properties<K>(
&self,
source: &JsValue,
excluded_keys: Vec<K>,
context: &mut Context,
) -> JsResult<()>
where
K: Into<PropertyKey>,
{
let context = &mut InternalMethodPropertyContext::new(context);

// 1. Assert: Type(target) is Object.
// 2. Assert: excludedItems is a List of property keys.
// 3. If source is undefined or null, return target.
if source.is_null_or_undefined() {
return Ok(());
}

// 4. Let from be ! ToObject(source).
let from = source
.to_object(context)
.expect("function ToObject should never complete abruptly here");

// 5. Let keys be ? from.[[OwnPropertyKeys]]().
// 6. For each element nextKey of keys, do
let excluded_keys: Vec<PropertyKey> = excluded_keys.into_iter().map(Into::into).collect();
for key in from.__own_property_keys__(context)? {
// a. Let excluded be false.
let mut excluded = false;

// b. For each element e of excludedItems, do
for e in &excluded_keys {
// i. If SameValue(e, nextKey) is true, then
if *e == key {
// 1. Set excluded to true.
excluded = true;
break;
}
}
// c. If excluded is false, then
if !excluded {
// i. Let desc be ? from.[[GetOwnProperty]](nextKey).
let desc = from.__get_own_property__(&key, context)?;

// ii. If desc is not undefined and desc.[[Enumerable]] is true, then
if let Some(desc) = desc
&& let Some(enumerable) = desc.enumerable()
&& enumerable
{
// 1. Let propValue be ? Get(from, nextKey).
let prop_value = from.__get__(&key, from.clone().into(), context)?;

// 2. Perform ! CreateDataPropertyOrThrow(target, nextKey, propValue).
self.create_data_property_or_throw(key, prop_value, context)
.expect("CreateDataPropertyOrThrow should never complete abruptly here");
}
}
}

// 7. Return target.
Ok(())
}

/// Abstract operation `PrivateElementFind ( O, P )`
///
Expand Down
33 changes: 9 additions & 24 deletions core/engine/src/vm/opcode/define/class/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,9 @@ impl DefineClassStaticMethodByName {
.set_home_object(class.clone());
}

class.__define_own_property__(
&key,
PropertyDescriptor::builder()
.value(function.clone())
.writable(true)
.enumerable(false)
.configurable(true)
.build(),
class.define_method_property(
key,
function.clone(),
&mut InternalMethodPropertyContext::new(context),
)?;
Ok(())
Expand Down Expand Up @@ -92,14 +87,9 @@ impl DefineClassMethodByName {
.set_home_object(class_proto.clone());
}

class_proto.__define_own_property__(
&key,
PropertyDescriptor::builder()
.value(function.clone())
.writable(true)
.enumerable(false)
.configurable(true)
.build(),
class_proto.define_method_property(
key,
function.clone(),
&mut InternalMethodPropertyContext::new(context),
)?;
Ok(())
Expand Down Expand Up @@ -194,14 +184,9 @@ impl DefineClassMethodByValue {
.set_home_object(class_proto.clone());
}

class_proto.__define_own_property__(
&key,
PropertyDescriptor::builder()
.value(function.clone())
.writable(true)
.enumerable(false)
.configurable(true)
.build(),
class_proto.define_method_property(
key,
function.clone(),
&mut InternalMethodPropertyContext::new(context),
)?;
Ok(())
Expand Down
Loading