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:
Linus Groh 2022-08-13 23:55:41 +01:00
parent 913412e0c5
commit 849495915b
Notes: sideshowbarker 2024-07-17 08:19:15 +09:00
3 changed files with 45 additions and 5 deletions

View file

@ -21,14 +21,14 @@
namespace JS {
FunctionPrototype::FunctionPrototype(GlobalObject& global_object)
: Object(*global_object.object_prototype())
: FunctionObject(*global_object.object_prototype())
{
}
void FunctionPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
Base::initialize(global_object);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.apply, apply, 2, 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);
}
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
JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply)
{

View file

@ -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
*/
@ -10,20 +10,27 @@
namespace JS {
class FunctionPrototype final : public Object {
JS_OBJECT(FunctionPrototype, Object);
class FunctionPrototype final : public FunctionObject {
JS_OBJECT(FunctionPrototype, FunctionObject);
public:
explicit FunctionPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
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:
JS_DECLARE_NATIVE_FUNCTION(apply);
JS_DECLARE_NATIVE_FUNCTION(bind);
JS_DECLARE_NATIVE_FUNCTION(call);
JS_DECLARE_NATIVE_FUNCTION(to_string);
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" };
};
}

View file

@ -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')"
);
});
});