1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 15:48:12 +00:00

LibJS: Bring Reflect.construct() closer to the specification

This includes checking that the target is a constructor, not just a
function, as well as switching the order of the list creation and
argument validation to match the specification, to ensure correct
exception throwing order.
This commit is contained in:
Idan Horowitz 2021-06-28 13:49:35 +03:00 committed by Linus Groh
parent 596324ae9c
commit 8eb48039c9
3 changed files with 21 additions and 24 deletions

View file

@ -26,17 +26,6 @@ static Object* get_target_object_from(GlobalObject& global_object, const String&
return static_cast<Object*>(&target.as_object());
}
static FunctionObject* get_target_function_from(GlobalObject& global_object, const String& name)
{
auto& vm = global_object.vm();
auto target = vm.argument(0);
if (!target.is_function()) {
vm.throw_exception<TypeError>(global_object, ErrorType::ReflectArgumentMustBeAFunction, name);
return nullptr;
}
return &target.as_function();
}
ReflectObject::ReflectObject(GlobalObject& global_object)
: Object(*global_object.object_prototype())
{
@ -72,36 +61,43 @@ ReflectObject::~ReflectObject()
// 28.1.1 Reflect.apply ( target, thisArgument, argumentsList ), https://tc39.es/ecma262/#sec-reflect.apply
JS_DEFINE_NATIVE_FUNCTION(ReflectObject::apply)
{
auto* target = get_target_function_from(global_object, "apply");
if (!target)
auto target = vm.argument(0);
if (!target.is_function()) {
vm.throw_exception<TypeError>(global_object, ErrorType::ReflectArgumentMustBeAFunction, vm.names.apply);
return {};
}
auto this_arg = vm.argument(1);
auto arguments = create_list_from_array_like(global_object, vm.argument(2));
if (vm.exception())
return {};
return vm.call(*target, this_arg, move(arguments));
return vm.call(target.as_function(), this_arg, move(arguments));
}
// 28.1.2 Reflect.construct ( target, argumentsList [ , newTarget ] ), https://tc39.es/ecma262/#sec-reflect.construct
JS_DEFINE_NATIVE_FUNCTION(ReflectObject::construct)
{
auto* target = get_target_function_from(global_object, "construct");
if (!target)
auto target = vm.argument(0);
if (!target.is_constructor()) {
vm.throw_exception<TypeError>(global_object, ErrorType::ReflectArgumentMustBeAConstructor, vm.names.construct);
return {};
auto arguments = create_list_from_array_like(global_object, vm.argument(1));
if (vm.exception())
return {};
auto* new_target = target;
}
auto* new_target = &target.as_function();
if (vm.argument_count() > 2) {
auto new_target_value = vm.argument(2);
if (!new_target_value.is_function()
|| (is<NativeFunction>(new_target_value.as_object()) && !static_cast<NativeFunction&>(new_target_value.as_object()).has_constructor())) {
if (!new_target_value.is_constructor()) {
vm.throw_exception<TypeError>(global_object, ErrorType::ReflectBadNewTarget);
return {};
}
new_target = &new_target_value.as_function();
}
return vm.construct(*target, *new_target, move(arguments));
auto arguments = create_list_from_array_like(global_object, vm.argument(1));
if (vm.exception())
return {};
return vm.construct(target.as_function(), *new_target, move(arguments));
}
// 28.1.3 Reflect.defineProperty ( target, propertyKey, attributes ), https://tc39.es/ecma262/#sec-reflect.defineproperty