mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 12:37:44 +00:00
LibJS: Make Function.prototype a callable function object
20.2.3 Properties of the Function Prototype Object https://tc39.es/ecma262/#sec-properties-of-the-function-prototype-object The Function prototype object: - is itself a built-in function object.
This commit is contained in:
parent
913412e0c5
commit
849495915b
3 changed files with 45 additions and 5 deletions
|
@ -21,14 +21,14 @@
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
FunctionPrototype::FunctionPrototype(GlobalObject& global_object)
|
FunctionPrototype::FunctionPrototype(GlobalObject& global_object)
|
||||||
: Object(*global_object.object_prototype())
|
: FunctionObject(*global_object.object_prototype())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionPrototype::initialize(GlobalObject& global_object)
|
void FunctionPrototype::initialize(GlobalObject& global_object)
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
Object::initialize(global_object);
|
Base::initialize(global_object);
|
||||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||||
define_native_function(vm.names.apply, apply, 2, attr);
|
define_native_function(vm.names.apply, apply, 2, attr);
|
||||||
define_native_function(vm.names.bind, bind, 1, attr);
|
define_native_function(vm.names.bind, bind, 1, attr);
|
||||||
|
@ -39,6 +39,13 @@ void FunctionPrototype::initialize(GlobalObject& global_object)
|
||||||
define_direct_property(vm.names.name, js_string(heap(), ""), Attribute::Configurable);
|
define_direct_property(vm.names.name, js_string(heap(), ""), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThrowCompletionOr<Value> FunctionPrototype::internal_call(Value, MarkedVector<Value>)
|
||||||
|
{
|
||||||
|
// The Function prototype object:
|
||||||
|
// - accepts any arguments and returns undefined when invoked.
|
||||||
|
return js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
// 20.2.3.1 Function.prototype.apply ( thisArg, argArray ), https://tc39.es/ecma262/#sec-function.prototype.apply
|
// 20.2.3.1 Function.prototype.apply ( thisArg, argArray ), https://tc39.es/ecma262/#sec-function.prototype.apply
|
||||||
JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply)
|
JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, Linus Groh <linusg@serenityos.org>
|
* Copyright (c) 2020-2022, Linus Groh <linusg@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -10,20 +10,27 @@
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
class FunctionPrototype final : public Object {
|
class FunctionPrototype final : public FunctionObject {
|
||||||
JS_OBJECT(FunctionPrototype, Object);
|
JS_OBJECT(FunctionPrototype, FunctionObject);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit FunctionPrototype(GlobalObject&);
|
explicit FunctionPrototype(GlobalObject&);
|
||||||
virtual void initialize(GlobalObject&) override;
|
virtual void initialize(GlobalObject&) override;
|
||||||
virtual ~FunctionPrototype() override = default;
|
virtual ~FunctionPrototype() override = default;
|
||||||
|
|
||||||
|
virtual ThrowCompletionOr<Value> internal_call(Value this_argument, MarkedVector<Value> arguments_list) override;
|
||||||
|
virtual FlyString const& name() const override { return m_name; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JS_DECLARE_NATIVE_FUNCTION(apply);
|
JS_DECLARE_NATIVE_FUNCTION(apply);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(bind);
|
JS_DECLARE_NATIVE_FUNCTION(bind);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(call);
|
JS_DECLARE_NATIVE_FUNCTION(call);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(to_string);
|
JS_DECLARE_NATIVE_FUNCTION(to_string);
|
||||||
JS_DECLARE_NATIVE_FUNCTION(symbol_has_instance);
|
JS_DECLARE_NATIVE_FUNCTION(symbol_has_instance);
|
||||||
|
|
||||||
|
// Totally unnecessary, but sadly still necessary.
|
||||||
|
// TODO: Get rid of the pointless name() method.
|
||||||
|
FlyString m_name { "FunctionPrototype" };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
describe("correct behavior", () => {
|
||||||
|
test("length is 0", () => {
|
||||||
|
expect(Function.prototype).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("name is empty string", () => {
|
||||||
|
expect(Function.prototype.name).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("basic functionality", () => {
|
||||||
|
function fn() {}
|
||||||
|
expect(Object.getPrototypeOf(fn)).toBe(Function.prototype);
|
||||||
|
expect(Object.getPrototypeOf(Function.prototype)).toBe(Object.prototype);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("is callable", () => {
|
||||||
|
expect(Function.prototype()).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("is not constructable", () => {
|
||||||
|
expect(() => new Function.prototype()).toThrowWithMessage(
|
||||||
|
TypeError,
|
||||||
|
"[object FunctionPrototype] is not a constructor (evaluated from 'Function.prototype')"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue