Skip to content

Commit 1a87a5a

Browse files
committed
Implement Object.getOwnPropertyDescriptor
- Implement Object.getOwnPropertyDescriptor in src/js_object.rs - Add argument validation to throw TypeError for non-objects - Construct property descriptor objects correctly for data and accessor properties - Correctly map internal Value variants to spec-compliant descriptors - Increase test262 CI run limit to 40
1 parent adad1a6 commit 1a87a5a

File tree

2 files changed

+134
-1
lines changed

2 files changed

+134
-1
lines changed

.github/workflows/test262.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
env:
2929
FAIL_ON_FAILURE: 'true'
3030
run: |
31-
bash ci/run_test262.sh --limit 30 --fail-on-failure --focus language
31+
bash ci/run_test262.sh --limit 40 --fail-on-failure --focus language
3232
3333
- name: Upload results
3434
if: ${{ !cancelled() }}

src/js_object.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,139 @@ pub fn handle_object_method<'gc>(
472472
_ => Err(raise_type_error!("Object.getOwnPropertyNames called on non-object")),
473473
}
474474
}
475+
"getOwnPropertyDescriptor" => {
476+
if args.len() < 2 {
477+
return Err(raise_type_error!("Object.getOwnPropertyDescriptor requires at least two arguments"));
478+
}
479+
let obj_val = args[0].clone();
480+
let obj = match obj_val {
481+
Value::Object(o) => o,
482+
_ => return Err(raise_type_error!("Object.getOwnPropertyDescriptor called on non-object")),
483+
};
484+
485+
let prop_val = args[1].clone();
486+
let key = match prop_val {
487+
Value::String(s) => PropertyKey::String(utf16_to_utf8(&s)),
488+
Value::BigInt(b) => PropertyKey::String(b.to_string()),
489+
Value::Symbol(sd) => PropertyKey::Symbol(sd),
490+
val => PropertyKey::String(value_to_string(&val)),
491+
};
492+
493+
if let Some(val_rc) = object_get_key_value(&obj, &key) {
494+
let desc_obj = new_js_object_data(mc);
495+
496+
match &*val_rc.borrow() {
497+
Value::Property { value, getter, setter } => {
498+
if let Some(v) = value {
499+
object_set_key_value(mc, &desc_obj, "value", v.borrow().clone())?;
500+
object_set_key_value(mc, &desc_obj, "writable", Value::Boolean(true))?;
501+
}
502+
if let Some(g) = getter {
503+
match &*g.clone() {
504+
Value::Getter(body, captured_env, _home) => {
505+
let func_obj = crate::core::new_js_object_data(mc);
506+
let closure_data = crate::core::ClosureData {
507+
params: Vec::new(),
508+
body: body.clone(),
509+
env: *captured_env,
510+
home_object: crate::core::GcCell::new(None),
511+
captured_envs: Vec::new(),
512+
bound_this: None,
513+
is_arrow: false,
514+
};
515+
let closure_val = crate::core::Value::Closure(crate::core::Gc::new(mc, closure_data));
516+
object_set_key_value(mc, &func_obj, "__closure__", closure_val)?;
517+
object_set_key_value(mc, &desc_obj, "get", Value::Object(func_obj))?;
518+
}
519+
other => {
520+
object_set_key_value(mc, &desc_obj, "get", other.clone())?;
521+
}
522+
}
523+
}
524+
if let Some(s) = setter {
525+
match &*s.clone() {
526+
Value::Setter(params, body, captured_env, _home) => {
527+
let func_obj = crate::core::new_js_object_data(mc);
528+
let closure_data = crate::core::ClosureData {
529+
params: params.clone(),
530+
body: body.clone(),
531+
env: *captured_env,
532+
home_object: crate::core::GcCell::new(None),
533+
captured_envs: Vec::new(),
534+
bound_this: None,
535+
is_arrow: false,
536+
};
537+
let closure_val = crate::core::Value::Closure(crate::core::Gc::new(mc, closure_data));
538+
object_set_key_value(mc, &func_obj, "__closure__", closure_val)?;
539+
object_set_key_value(mc, &desc_obj, "set", Value::Object(func_obj))?;
540+
}
541+
other => {
542+
object_set_key_value(mc, &desc_obj, "set", other.clone())?;
543+
}
544+
}
545+
}
546+
547+
let enum_flag = Value::Boolean(obj.borrow().is_enumerable(&key));
548+
object_set_key_value(mc, &desc_obj, "enumerable", enum_flag)?;
549+
let config_flag = Value::Boolean(obj.borrow().is_configurable(&key));
550+
object_set_key_value(mc, &desc_obj, "configurable", config_flag)?;
551+
}
552+
Value::Getter(body, captured_env, _home_opt) => {
553+
let func_obj = crate::core::new_js_object_data(mc);
554+
let closure_data = crate::core::ClosureData {
555+
params: Vec::new(),
556+
body: body.clone(),
557+
env: *captured_env,
558+
home_object: crate::core::GcCell::new(None),
559+
captured_envs: Vec::new(),
560+
bound_this: None,
561+
is_arrow: false,
562+
};
563+
let closure_val = crate::core::Value::Closure(crate::core::Gc::new(mc, closure_data));
564+
object_set_key_value(mc, &func_obj, "__closure__", closure_val)?;
565+
object_set_key_value(mc, &desc_obj, "get", Value::Object(func_obj))?;
566+
567+
let enum_flag = Value::Boolean(obj.borrow().is_enumerable(&key));
568+
object_set_key_value(mc, &desc_obj, "enumerable", enum_flag)?;
569+
let config_flag = Value::Boolean(obj.borrow().is_configurable(&key));
570+
object_set_key_value(mc, &desc_obj, "configurable", config_flag)?;
571+
}
572+
Value::Setter(params, body, captured_env, _home_opt) => {
573+
let func_obj = crate::core::new_js_object_data(mc);
574+
let closure_data = crate::core::ClosureData {
575+
params: params.clone(),
576+
body: body.clone(),
577+
env: *captured_env,
578+
home_object: crate::core::GcCell::new(None),
579+
captured_envs: Vec::new(),
580+
bound_this: None,
581+
is_arrow: false,
582+
};
583+
let closure_val = crate::core::Value::Closure(crate::core::Gc::new(mc, closure_data));
584+
object_set_key_value(mc, &func_obj, "__closure__", closure_val)?;
585+
object_set_key_value(mc, &desc_obj, "set", Value::Object(func_obj))?;
586+
587+
let enum_flag = Value::Boolean(obj.borrow().is_enumerable(&key));
588+
object_set_key_value(mc, &desc_obj, "enumerable", enum_flag)?;
589+
let config_flag = Value::Boolean(obj.borrow().is_configurable(&key));
590+
object_set_key_value(mc, &desc_obj, "configurable", config_flag)?;
591+
}
592+
other => {
593+
object_set_key_value(mc, &desc_obj, "value", other.clone())?;
594+
let writable_flag = Value::Boolean(obj.borrow().is_writable(&key));
595+
object_set_key_value(mc, &desc_obj, "writable", writable_flag)?;
596+
let enum_flag = Value::Boolean(obj.borrow().is_enumerable(&key));
597+
object_set_key_value(mc, &desc_obj, "enumerable", enum_flag)?;
598+
let config_flag = Value::Boolean(obj.borrow().is_configurable(&key));
599+
object_set_key_value(mc, &desc_obj, "configurable", config_flag)?;
600+
}
601+
}
602+
603+
Ok(Value::Object(desc_obj))
604+
} else {
605+
Ok(Value::Undefined)
606+
}
607+
}
475608
"getOwnPropertyDescriptors" => {
476609
if args.len() != 1 {
477610
return Err(raise_type_error!("Object.getOwnPropertyDescriptors requires exactly one argument"));

0 commit comments

Comments
 (0)