Skip to content

Commit 57ebbbd

Browse files
MayankRaj435Your Namealienx5499ashddev
authored
Spec alignment create method property (#5013)
This PR aligns Boa more closely with the ECMAScript specification by implementing missing abstract operations and centralizing them in [operations.rs](file:///home/mayank/boa/core/engine/src/object/operations.rs). #### **1. Implement `CreateMethodProperty` ([§7.3.5](https://tc39.es/ecma262/#sec-createmethodproperty))** Added the [create_method_property](file:///home/mayank/boa/core/engine/src/object/operations.rs#180-208) helper to [core/engine/src/object/operations.rs](file:///home/mayank/boa/core/engine/src/object/operations.rs). **Before:** ```rust // core/engine/src/object/operations.rs // todo: CreateMethodProperty ``` **After:** ```rust pub(crate) fn create_method_property<K, V>( &self, key: K, value: V, context: &mut InternalMethodPropertyContext<'_>, ) -> JsResult<bool> where K: Into<PropertyKey>, V: Into<JsValue>, { let new_desc = PropertyDescriptor::builder() .value(value) .writable(true) .enumerable(false) .configurable(true); self.__define_own_property__(&key.into(), new_desc.into(), context) } ``` #### **2. Move [CopyDataProperties](file:///home/mayank/boa/core/engine/src/vm/opcode/copy/mod.rs#10-11) ([§7.3.26](https://tc39.es/ecma262/#sec-copydataproperties))** Moved the implementation from [jsobject.rs](file:///home/mayank/boa/core/engine/src/object/jsobject.rs) to [operations.rs](file:///home/mayank/boa/core/engine/src/object/operations.rs) to center abstract operations as suggested by internal `todo` comments. **Before:** - [jsobject.rs](file:///home/mayank/boa/core/engine/src/object/jsobject.rs): Contained the implementation of [copy_data_properties](file:///home/mayank/boa/core/engine/src/object/operations.rs#872-940). - [operations.rs](file:///home/mayank/boa/core/engine/src/object/operations.rs): Contained `// todo: CopyDataProperties`. **After:** - [jsobject.rs](file:///home/mayank/boa/core/engine/src/object/jsobject.rs): Implementation removed. - [operations.rs](file:///home/mayank/boa/core/engine/src/object/operations.rs): ```rust pub fn copy_data_properties<K>( &self, source: &JsValue, excluded_keys: Vec<K>, context: &mut Context, ) -> JsResult<()> { // ... (Implementation moved here) } ``` ### **Tests** - Verified with `cargo check -p boa_engine`. - Confirmed formatting with `cargo fmt`. --------- Co-authored-by: Your Name <test@example.com> Co-authored-by: Prabal Patra <163229512+alienx5499@users.noreply.github.com> Co-authored-by: ash <ashddev@proton.me>
1 parent 1848e23 commit 57ebbbd

File tree

3 files changed

+113
-98
lines changed

3 files changed

+113
-98
lines changed

core/engine/src/object/jsobject.rs

Lines changed: 1 addition & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
55
use super::{
66
JsPrototype, NativeObject, Object, ObjectData, PrivateName, PropertyMap,
7-
internal_methods::{
8-
InternalMethodPropertyContext, InternalObjectMethods, ORDINARY_INTERNAL_METHODS,
9-
},
7+
internal_methods::{InternalObjectMethods, ORDINARY_INTERNAL_METHODS},
108
shape::RootShape,
119
};
1210
use crate::{
@@ -768,75 +766,6 @@ Cannot both specify accessors and a value or writable attribute",
768766
Ok(desc.build())
769767
}
770768

771-
/// `7.3.25 CopyDataProperties ( target, source, excludedItems )`
772-
///
773-
/// More information:
774-
/// - [ECMAScript][spec]
775-
///
776-
/// [spec]: https://tc39.es/ecma262/#sec-copydataproperties
777-
pub fn copy_data_properties<K>(
778-
&self,
779-
source: &JsValue,
780-
excluded_keys: Vec<K>,
781-
context: &mut Context,
782-
) -> JsResult<()>
783-
where
784-
K: Into<PropertyKey>,
785-
{
786-
let context = &mut InternalMethodPropertyContext::new(context);
787-
788-
// 1. Assert: Type(target) is Object.
789-
// 2. Assert: excludedItems is a List of property keys.
790-
// 3. If source is undefined or null, return target.
791-
if source.is_null_or_undefined() {
792-
return Ok(());
793-
}
794-
795-
// 4. Let from be ! ToObject(source).
796-
let from = source
797-
.to_object(context)
798-
.expect("function ToObject should never complete abruptly here");
799-
800-
// 5. Let keys be ? from.[[OwnPropertyKeys]]().
801-
// 6. For each element nextKey of keys, do
802-
let excluded_keys: Vec<PropertyKey> = excluded_keys.into_iter().map(Into::into).collect();
803-
for key in from.__own_property_keys__(context)? {
804-
// a. Let excluded be false.
805-
let mut excluded = false;
806-
807-
// b. For each element e of excludedItems, do
808-
for e in &excluded_keys {
809-
// i. If SameValue(e, nextKey) is true, then
810-
if *e == key {
811-
// 1. Set excluded to true.
812-
excluded = true;
813-
break;
814-
}
815-
}
816-
// c. If excluded is false, then
817-
if !excluded {
818-
// i. Let desc be ? from.[[GetOwnProperty]](nextKey).
819-
let desc = from.__get_own_property__(&key, context)?;
820-
821-
// ii. If desc is not undefined and desc.[[Enumerable]] is true, then
822-
if let Some(desc) = desc
823-
&& let Some(enumerable) = desc.enumerable()
824-
&& enumerable
825-
{
826-
// 1. Let propValue be ? Get(from, nextKey).
827-
let prop_value = from.__get__(&key, from.clone().into(), context)?;
828-
829-
// 2. Perform ! CreateDataPropertyOrThrow(target, nextKey, propValue).
830-
self.create_data_property_or_throw(key, prop_value, context)
831-
.expect("CreateDataPropertyOrThrow should never complete abruptly here");
832-
}
833-
}
834-
}
835-
836-
// 7. Return target.
837-
Ok(())
838-
}
839-
840769
// Allow lint, false positive.
841770
#[allow(clippy::assigning_clones)]
842771
pub(crate) fn get_property(&self, key: &PropertyKey) -> Option<PropertyDescriptor> {

core/engine/src/object/operations.rs

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,41 @@ impl JsObject {
177177
self.__define_own_property__(&key.into(), new_desc.into(), context)
178178
}
179179

180-
// todo: CreateMethodProperty
180+
/// `10.2.8 DefineMethodProperty ( homeObject, key, closure, enumerable )`
181+
///
182+
/// Defines a method property on an object with the specified attributes.
183+
///
184+
/// More information:
185+
/// - [ECMAScript reference][spec]
186+
///
187+
/// [spec]: https://tc39.es/ecma262/#sec-definemethodproperty
188+
pub(crate) fn define_method_property<K, V>(
189+
&self,
190+
key: K,
191+
value: V,
192+
context: &mut InternalMethodPropertyContext<'_>,
193+
) -> JsResult<()>
194+
where
195+
K: Into<PropertyKey>,
196+
V: Into<JsValue>,
197+
{
198+
// 1. Assert: homeObject is an ordinary, extensible object with no non-configurable properties.
199+
// 2. If key is a Private Name, then
200+
// a. Return PrivateElement { [[Key]]: key, [[Kind]]: method, [[Value]]: closure }.
201+
// 3. Else,
202+
// a. Let desc be the PropertyDescriptor { [[Value]]: closure, [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true }.
203+
let new_desc = PropertyDescriptor::builder()
204+
.value(value)
205+
.writable(true)
206+
.enumerable(false)
207+
.configurable(true);
208+
209+
// b. Perform ! DefinePropertyOrThrow(homeObject, key, desc).
210+
self.__define_own_property__(&key.into(), new_desc.into(), context)?;
211+
212+
// c. Return unused.
213+
Ok(())
214+
}
181215

182216
/// Create data property or throw
183217
///
@@ -842,7 +876,74 @@ impl JsObject {
842876
Ok(context.realm().clone())
843877
}
844878

845-
// todo: CopyDataProperties
879+
/// `7.3.26 CopyDataProperties ( target, source, excludedItems )`
880+
///
881+
/// More information:
882+
/// - [ECMAScript reference][spec]
883+
///
884+
/// [spec]: https://tc39.es/ecma262/#sec-copydataproperties
885+
pub fn copy_data_properties<K>(
886+
&self,
887+
source: &JsValue,
888+
excluded_keys: Vec<K>,
889+
context: &mut Context,
890+
) -> JsResult<()>
891+
where
892+
K: Into<PropertyKey>,
893+
{
894+
let context = &mut InternalMethodPropertyContext::new(context);
895+
896+
// 1. Assert: Type(target) is Object.
897+
// 2. Assert: excludedItems is a List of property keys.
898+
// 3. If source is undefined or null, return target.
899+
if source.is_null_or_undefined() {
900+
return Ok(());
901+
}
902+
903+
// 4. Let from be ! ToObject(source).
904+
let from = source
905+
.to_object(context)
906+
.expect("function ToObject should never complete abruptly here");
907+
908+
// 5. Let keys be ? from.[[OwnPropertyKeys]]().
909+
// 6. For each element nextKey of keys, do
910+
let excluded_keys: Vec<PropertyKey> = excluded_keys.into_iter().map(Into::into).collect();
911+
for key in from.__own_property_keys__(context)? {
912+
// a. Let excluded be false.
913+
let mut excluded = false;
914+
915+
// b. For each element e of excludedItems, do
916+
for e in &excluded_keys {
917+
// i. If SameValue(e, nextKey) is true, then
918+
if *e == key {
919+
// 1. Set excluded to true.
920+
excluded = true;
921+
break;
922+
}
923+
}
924+
// c. If excluded is false, then
925+
if !excluded {
926+
// i. Let desc be ? from.[[GetOwnProperty]](nextKey).
927+
let desc = from.__get_own_property__(&key, context)?;
928+
929+
// ii. If desc is not undefined and desc.[[Enumerable]] is true, then
930+
if let Some(desc) = desc
931+
&& let Some(enumerable) = desc.enumerable()
932+
&& enumerable
933+
{
934+
// 1. Let propValue be ? Get(from, nextKey).
935+
let prop_value = from.__get__(&key, from.clone().into(), context)?;
936+
937+
// 2. Perform ! CreateDataPropertyOrThrow(target, nextKey, propValue).
938+
self.create_data_property_or_throw(key, prop_value, context)
939+
.expect("CreateDataPropertyOrThrow should never complete abruptly here");
940+
}
941+
}
942+
}
943+
944+
// 7. Return target.
945+
Ok(())
946+
}
846947

847948
/// Abstract operation `PrivateElementFind ( O, P )`
848949
///

core/engine/src/vm/opcode/define/class/method.rs

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,9 @@ impl DefineClassStaticMethodByName {
3939
.set_home_object(class.clone());
4040
}
4141

42-
class.__define_own_property__(
43-
&key,
44-
PropertyDescriptor::builder()
45-
.value(function.clone())
46-
.writable(true)
47-
.enumerable(false)
48-
.configurable(true)
49-
.build(),
42+
class.define_method_property(
43+
key,
44+
function.clone(),
5045
&mut InternalMethodPropertyContext::new(context),
5146
)?;
5247
Ok(())
@@ -92,14 +87,9 @@ impl DefineClassMethodByName {
9287
.set_home_object(class_proto.clone());
9388
}
9489

95-
class_proto.__define_own_property__(
96-
&key,
97-
PropertyDescriptor::builder()
98-
.value(function.clone())
99-
.writable(true)
100-
.enumerable(false)
101-
.configurable(true)
102-
.build(),
90+
class_proto.define_method_property(
91+
key,
92+
function.clone(),
10393
&mut InternalMethodPropertyContext::new(context),
10494
)?;
10595
Ok(())
@@ -194,14 +184,9 @@ impl DefineClassMethodByValue {
194184
.set_home_object(class_proto.clone());
195185
}
196186

197-
class_proto.__define_own_property__(
198-
&key,
199-
PropertyDescriptor::builder()
200-
.value(function.clone())
201-
.writable(true)
202-
.enumerable(false)
203-
.configurable(true)
204-
.build(),
187+
class_proto.define_method_property(
188+
key,
189+
function.clone(),
205190
&mut InternalMethodPropertyContext::new(context),
206191
)?;
207192
Ok(())

0 commit comments

Comments
 (0)