summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2022-08-13 23:55:41 +0100
committerLinus Groh <mail@linusgroh.de>2022-08-14 00:44:27 +0100
commit849495915b0084774a0b3d5a0e05f01434f79aa5 (patch)
tree79d6bbdc9a5f2a17f01d0aafa765fd84b94b591e
parent913412e0c540a0d9f119e5575613162f2095d00c (diff)
downloadserenity-849495915b0084774a0b3d5a0e05f01434f79aa5.zip
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.
-rw-r--r--Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp11
-rw-r--r--Userland/Libraries/LibJS/Runtime/FunctionPrototype.h13
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Function/Function.prototype.js26
3 files changed, 45 insertions, 5 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp
index e1fbd55190..2fab7b2f4f 100644
--- a/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp
@@ -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)
{
diff --git a/Userland/Libraries/LibJS/Runtime/FunctionPrototype.h b/Userland/Libraries/LibJS/Runtime/FunctionPrototype.h
index 1603f96068..ffaa42a0ed 100644
--- a/Userland/Libraries/LibJS/Runtime/FunctionPrototype.h
+++ b/Userland/Libraries/LibJS/Runtime/FunctionPrototype.h
@@ -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" };
};
}
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Function/Function.prototype.js b/Userland/Libraries/LibJS/Tests/builtins/Function/Function.prototype.js
new file mode 100644
index 0000000000..fe3a8ce4bb
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/builtins/Function/Function.prototype.js
@@ -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')"
+ );
+ });
+});