fix: 绑定 Function 和 Object prototype harness helper
This commit is contained in:
@@ -58,6 +58,8 @@ pub struct ObjectMethods {
|
|||||||
pub has_own: *const (),
|
pub has_own: *const (),
|
||||||
pub entries: *const (),
|
pub entries: *const (),
|
||||||
pub values: *const (),
|
pub values: *const (),
|
||||||
|
pub has_own_property: *const (),
|
||||||
|
pub property_is_enumerable: *const (),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ArrayMethods {
|
pub struct ArrayMethods {
|
||||||
@@ -408,6 +410,17 @@ impl BuiltinWorld {
|
|||||||
("entries", methods.entries, 1),
|
("entries", methods.entries, 1),
|
||||||
("values", methods.values, 1),
|
("values", methods.values, 1),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let proto_ptr = P::as_ptr(&self.object_proto) as *mut JsObject;
|
||||||
|
let proto = unsafe { &mut *proto_ptr };
|
||||||
|
bind_methods!(
|
||||||
|
self,
|
||||||
|
proto,
|
||||||
|
string_forge,
|
||||||
|
shape_forge,
|
||||||
|
("hasOwnProperty", methods.has_own_property, 1),
|
||||||
|
("propertyIsEnumerable", methods.property_is_enumerable, 1),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind_array_methods(&self, methods: &ArrayMethods, string_forge: &StringForge, shape_forge: &ShapeForge) {
|
pub fn bind_array_methods(&self, methods: &ArrayMethods, string_forge: &StringForge, shape_forge: &ShapeForge) {
|
||||||
|
|||||||
@@ -2,8 +2,12 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use oxide_kernel::builtin::FunctionMethods;
|
use oxide_kernel::builtin::FunctionMethods;
|
||||||
use oxide_kernel::kernel::OxideKernel;
|
use oxide_kernel::kernel::OxideKernel;
|
||||||
|
use oxide_types::object::JsObject;
|
||||||
|
use oxide_types::value::JsValue;
|
||||||
|
|
||||||
pub fn bind_function(kernel: &Arc<OxideKernel>) {
|
use super::bind_global_value;
|
||||||
|
|
||||||
|
pub fn bind_function(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
|
||||||
let function_methods = FunctionMethods {
|
let function_methods = FunctionMethods {
|
||||||
call: crate::builtins::function::function_call as *const (),
|
call: crate::builtins::function::function_call as *const (),
|
||||||
apply: crate::builtins::function::function_apply as *const (),
|
apply: crate::builtins::function::function_apply as *const (),
|
||||||
@@ -15,4 +19,7 @@ pub fn bind_function(kernel: &Arc<OxideKernel>) {
|
|||||||
kernel.string_forge().as_ref(),
|
kernel.string_forge().as_ref(),
|
||||||
kernel.shape_forge().as_ref(),
|
kernel.shape_forge().as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let function_ctor = kernel.builtin_world().function_constructor.as_ptr() as *mut JsObject;
|
||||||
|
bind_global_value(kernel, global, "Function", JsValue::from_js_object(function_ctor));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ pub fn bind_object(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
|
|||||||
has_own: crate::builtins::object::object_has_own as *const (),
|
has_own: crate::builtins::object::object_has_own as *const (),
|
||||||
entries: crate::builtins::object::object_entries as *const (),
|
entries: crate::builtins::object::object_entries as *const (),
|
||||||
values: crate::builtins::object::object_values as *const (),
|
values: crate::builtins::object::object_values as *const (),
|
||||||
|
has_own_property: crate::builtins::object::object_proto_has_own_property as *const (),
|
||||||
|
property_is_enumerable: crate::builtins::object::object_proto_property_is_enumerable as *const (),
|
||||||
};
|
};
|
||||||
kernel
|
kernel
|
||||||
.builtin_world()
|
.builtin_world()
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
|
|||||||
bind_set::bind_set(kernel, global);
|
bind_set::bind_set(kernel, global);
|
||||||
bind_map::bind_map(kernel, global);
|
bind_map::bind_map(kernel, global);
|
||||||
bind_boolean::bind_boolean(kernel, global);
|
bind_boolean::bind_boolean(kernel, global);
|
||||||
bind_function::bind_function(kernel);
|
bind_function::bind_function(kernel, global);
|
||||||
bind_regexp::bind_regexp(kernel, global);
|
bind_regexp::bind_regexp(kernel, global);
|
||||||
bind_symbol::bind_symbol(kernel, global);
|
bind_symbol::bind_symbol(kernel, global);
|
||||||
|
|
||||||
|
|||||||
@@ -447,12 +447,49 @@ pub fn object_has_own(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
|||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
return Ok(JsValue::bool(false));
|
return Ok(JsValue::bool(false));
|
||||||
}
|
}
|
||||||
let _obj_ptr = require_obj_arg(vm, args, "hasOwn")?;
|
let obj_ptr = require_obj_arg(vm, args, "hasOwn")?;
|
||||||
let key_val = vm.reg(args[2]);
|
let key_si = vm.property_key_si(vm.reg(args[2]));
|
||||||
if !key_val.is_string() {
|
let obj = unsafe { &*obj_ptr };
|
||||||
|
Ok(JsValue::bool(vm.get_own_property_slot(obj, key_si).is_some()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn object_proto_has_own_property(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||||
|
if args.len() < 2 {
|
||||||
return Ok(JsValue::bool(false));
|
return Ok(JsValue::bool(false));
|
||||||
}
|
}
|
||||||
Ok(JsValue::bool(false))
|
let this_val = vm.reg(args[0]);
|
||||||
|
if !this_val.is_object() || this_val.as_js_object_ptr().is_null() {
|
||||||
|
return Err(crate::builtins::error::create_type_error(
|
||||||
|
vm,
|
||||||
|
"Object.prototype.hasOwnProperty called on non-object",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let key_si = vm.property_key_si(vm.reg(args[1]));
|
||||||
|
let obj = unsafe { &*this_val.as_js_object_ptr() };
|
||||||
|
Ok(JsValue::bool(vm.get_own_property_slot(obj, key_si).is_some()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn object_proto_property_is_enumerable(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||||
|
if args.len() < 2 {
|
||||||
|
return Ok(JsValue::bool(false));
|
||||||
|
}
|
||||||
|
let this_val = vm.reg(args[0]);
|
||||||
|
if !this_val.is_object() || this_val.as_js_object_ptr().is_null() {
|
||||||
|
return Err(crate::builtins::error::create_type_error(
|
||||||
|
vm,
|
||||||
|
"Object.prototype.propertyIsEnumerable called on non-object",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let key_si = vm.property_key_si(vm.reg(args[1]));
|
||||||
|
let obj = unsafe { &*this_val.as_js_object_ptr() };
|
||||||
|
let Some(pos) = vm.get_own_property_slot(obj, key_si) else {
|
||||||
|
return Ok(JsValue::bool(false));
|
||||||
|
};
|
||||||
|
let enumerable = obj
|
||||||
|
.prop_meta_at(pos)
|
||||||
|
.map(|meta| meta.attributes.enumerable())
|
||||||
|
.unwrap_or(PropAttributes::DEFAULT_DATA.enumerable());
|
||||||
|
Ok(JsValue::bool(enumerable))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn object_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
pub fn object_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||||
|
|||||||
@@ -30,6 +30,25 @@ fn function_bind_creates_wrapper() {
|
|||||||
assert!((result.as_double() - 5.0).abs() < 0.0001);
|
assert!((result.as_double() - 5.0).abs() < 0.0001);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_constructor_is_global() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, "typeof Function").unwrap();
|
||||||
|
let rendered = vm.kernel().string_forge().lookup(result.as_string_index()).unwrap_or_default();
|
||||||
|
assert_eq!(rendered, "function");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_call_bind_supports_uncurried_native_methods() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"var __push = Function.prototype.call.bind(Array.prototype.push); var a = []; __push(a, 'x'); a.length",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(result, JsValue::int(1));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn function_call_invokes_bytecode_function() {
|
fn function_call_invokes_bytecode_function() {
|
||||||
let mut vm = Vm::new();
|
let mut vm = Vm::new();
|
||||||
|
|||||||
@@ -118,7 +118,25 @@ fn object_get_prototype_of() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn object_has_own_true() {
|
fn object_has_own_true() {
|
||||||
let (_vm, result) = eval("Object.hasOwn({a:1}, 'a')").unwrap();
|
let (_vm, result) = eval("Object.hasOwn({a:1}, 'a')").unwrap();
|
||||||
assert!(result.is_bool());
|
assert_eq!(result, JsValue::bool(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn object_has_own_false_for_inherited_property() {
|
||||||
|
let (_vm, result) = eval("Object.hasOwn({}, 'toString')").unwrap();
|
||||||
|
assert_eq!(result, JsValue::bool(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn object_proto_has_own_property_call_works() {
|
||||||
|
let (_vm, result) = eval("Object.prototype.hasOwnProperty.call(Object, 'assign')").unwrap();
|
||||||
|
assert_eq!(result, JsValue::bool(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn object_proto_property_is_enumerable_call_works() {
|
||||||
|
let (_vm, result) = eval("Object.prototype.propertyIsEnumerable.call(Object, 'assign')").unwrap();
|
||||||
|
assert_eq!(result, JsValue::bool(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user