summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2021-06-15 00:04:08 -0700
committerLinus Groh <mail@linusgroh.de>2021-06-19 00:04:57 +0100
commit22b17219ff85f666f2ddc81347be8d6117740af6 (patch)
treea7aa282903bb27c01d027b96b31c23ff5f01ef37 /Userland
parentb205c9814a34210b42b582ed36eb2ede008ebfa6 (diff)
downloadserenity-22b17219ff85f666f2ddc81347be8d6117740af6.zip
LibJS: Add the remaining generator objects
- %GeneratorFunction% - %GeneratorFunction.prototype% - %GeneratorFunction.prototype.prototype% - %Generator%.prototype
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibJS/CMakeLists.txt3
-rw-r--r--Userland/Libraries/LibJS/Forward.h4
-rw-r--r--Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp2
-rw-r--r--Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp46
-rw-r--r--Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.h26
-rw-r--r--Userland/Libraries/LibJS/Runtime/GeneratorFunctionPrototype.cpp33
-rw-r--r--Userland/Libraries/LibJS/Runtime/GeneratorFunctionPrototype.h24
-rw-r--r--Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp59
-rw-r--r--Userland/Libraries/LibJS/Runtime/GeneratorObject.h11
-rw-r--r--Userland/Libraries/LibJS/Runtime/GeneratorObjectPrototype.cpp75
-rw-r--r--Userland/Libraries/LibJS/Runtime/GeneratorObjectPrototype.h28
-rw-r--r--Userland/Libraries/LibJS/Runtime/GlobalObject.cpp26
-rw-r--r--Userland/Libraries/LibJS/Runtime/GlobalObject.h6
-rw-r--r--Userland/Libraries/LibJS/Runtime/ScriptFunction.cpp26
14 files changed, 302 insertions, 67 deletions
diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt
index d218068f40..38e150f210 100644
--- a/Userland/Libraries/LibJS/CMakeLists.txt
+++ b/Userland/Libraries/LibJS/CMakeLists.txt
@@ -59,7 +59,10 @@ set(SOURCES
Runtime/FunctionConstructor.cpp
Runtime/Function.cpp
Runtime/FunctionPrototype.cpp
+ Runtime/GeneratorFunctionConstructor.cpp
+ Runtime/GeneratorFunctionPrototype.cpp
Runtime/GeneratorObject.cpp
+ Runtime/GeneratorObjectPrototype.cpp
Runtime/GlobalObject.cpp
Runtime/IndexedProperties.cpp
Runtime/IteratorOperations.cpp
diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h
index 4a4dd1eb7a..a8fae90d78 100644
--- a/Userland/Libraries/LibJS/Forward.h
+++ b/Userland/Libraries/LibJS/Forward.h
@@ -36,6 +36,7 @@
__JS_ENUMERATE(Error, error, ErrorPrototype, ErrorConstructor, void) \
__JS_ENUMERATE(FinalizationRegistry, finalization_registry, FinalizationRegistryPrototype, FinalizationRegistryConstructor, void) \
__JS_ENUMERATE(Function, function, FunctionPrototype, FunctionConstructor, void) \
+ __JS_ENUMERATE(GeneratorFunction, generator_function, GeneratorFunctionPrototype, GeneratorFunctionConstructor, void) \
__JS_ENUMERATE(Map, map, MapPrototype, MapConstructor, void) \
__JS_ENUMERATE(NumberObject, number, NumberPrototype, NumberConstructor, void) \
__JS_ENUMERATE(Object, object, ObjectPrototype, ObjectConstructor, void) \
@@ -159,6 +160,9 @@ struct PromiseCapability;
class ProxyObject;
class ProxyConstructor;
+// Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct constructor
+class GeneratorObjectPrototype;
+
class TypedArrayConstructor;
class TypedArrayPrototype;
diff --git a/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp b/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp
index 46e198b620..8918fb00b2 100644
--- a/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp
+++ b/Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp
@@ -31,11 +31,13 @@ FunctionConstructor::~FunctionConstructor()
{
}
+// 20.2.1.1 Function ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-function-p1-p2-pn-body
Value FunctionConstructor::call()
{
return construct(*this);
}
+// 20.2.1.1 Function ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-function-p1-p2-pn-body
Value FunctionConstructor::construct(Function&)
{
auto& vm = this->vm();
diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp b/Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp
new file mode 100644
index 0000000000..73fbe0fc02
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/FunctionConstructor.h>
+#include <LibJS/Runtime/Function.h>
+#include <LibJS/Runtime/GeneratorFunctionConstructor.h>
+#include <LibJS/Runtime/GlobalObject.h>
+
+namespace JS {
+
+GeneratorFunctionConstructor::GeneratorFunctionConstructor(GlobalObject& global_object)
+ : NativeFunction(*static_cast<Object*>(global_object.function_constructor()))
+{
+}
+
+void GeneratorFunctionConstructor::initialize(GlobalObject& global_object)
+{
+ auto& vm = this->vm();
+ NativeFunction::initialize(global_object);
+
+ // 27.3.2.1 GeneratorFunction.length, https://tc39.es/ecma262/#sec-generatorfunction.length
+ define_property(vm.names.length, Value(1), Attribute::Configurable);
+ // 27.3.2.2 GeneratorFunction.prototype, https://tc39.es/ecma262/#sec-generatorfunction.length
+ define_property(vm.names.prototype, global_object.generator_function_prototype(), 0);
+}
+
+GeneratorFunctionConstructor::~GeneratorFunctionConstructor()
+{
+}
+
+// 27.3.1.1 GeneratorFunction ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-generatorfunction
+Value GeneratorFunctionConstructor::call()
+{
+ return construct(*this);
+}
+
+// 27.3.1.1 GeneratorFunction ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-generatorfunction
+Value GeneratorFunctionConstructor::construct(Function&)
+{
+ TODO();
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.h b/Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.h
new file mode 100644
index 0000000000..0ad60b3f17
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/NativeFunction.h>
+
+namespace JS {
+
+// 27.3.1 %GeneratorFunction%, https://tc39.es/ecma262/#sec-generatorfunction-constructor
+class GeneratorFunctionConstructor final : public NativeFunction {
+ JS_OBJECT(GeneratorFunctionConstructor, NativeFunction);
+
+public:
+ explicit GeneratorFunctionConstructor(GlobalObject&);
+ virtual void initialize(GlobalObject&) override;
+ virtual ~GeneratorFunctionConstructor() override;
+
+ virtual Value call() override;
+ virtual Value construct(Function& new_target) override;
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorFunctionPrototype.cpp b/Userland/Libraries/LibJS/Runtime/GeneratorFunctionPrototype.cpp
new file mode 100644
index 0000000000..a2c7c6efa6
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/GeneratorFunctionPrototype.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/GeneratorFunctionConstructor.h>
+#include <LibJS/Runtime/GeneratorFunctionPrototype.h>
+#include <LibJS/Runtime/GeneratorObjectPrototype.h>
+
+namespace JS {
+
+GeneratorFunctionPrototype::GeneratorFunctionPrototype(GlobalObject& global_object)
+ : Object(*global_object.function_prototype())
+{
+}
+
+void GeneratorFunctionPrototype::initialize(GlobalObject& global_object)
+{
+ auto& vm = this->vm();
+ Object::initialize(global_object);
+
+ // 27.3.3.2 %GeneratorFunction.prototype% prototype, https://tc39.es/ecma262/#sec-generatorfunction.prototype.prototype
+ define_property(vm.names.prototype, global_object.generator_object_prototype(), Attribute::Configurable);
+ // 27.3.3.3 %GeneratorFunction.prototype% [ @@toStringTag ], https://tc39.es/ecma262/#sec-generatorfunction.prototype-@@tostringtag
+ define_property(vm.well_known_symbol_to_string_tag(), js_string(vm, "GeneratorFunction"), Attribute::Configurable);
+}
+
+GeneratorFunctionPrototype::~GeneratorFunctionPrototype()
+{
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorFunctionPrototype.h b/Userland/Libraries/LibJS/Runtime/GeneratorFunctionPrototype.h
new file mode 100644
index 0000000000..8bfe2fef09
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/GeneratorFunctionPrototype.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/Function.h>
+#include <LibJS/Runtime/GlobalObject.h>
+
+namespace JS {
+
+// 27.3.3 %GeneratorFunction.prototype%, https://tc39.es/ecma262/#sec-properties-of-the-generatorfunction-prototype-object
+class GeneratorFunctionPrototype final : public Object {
+ JS_OBJECT(GeneratorFunctionPrototype, Object);
+
+public:
+ explicit GeneratorFunctionPrototype(GlobalObject&);
+ virtual void initialize(GlobalObject&) override;
+ virtual ~GeneratorFunctionPrototype() override;
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp
index 559d55f6c3..845331143f 100644
--- a/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp
+++ b/Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp
@@ -8,13 +8,19 @@
#include <LibJS/Bytecode/Generator.h>
#include <LibJS/Bytecode/Interpreter.h>
#include <LibJS/Runtime/GeneratorObject.h>
+#include <LibJS/Runtime/GeneratorObjectPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
GeneratorObject* GeneratorObject::create(GlobalObject& global_object, Value initial_value, ScriptFunction* generating_function, ScopeObject* generating_scope, Bytecode::RegisterWindow frame)
{
- auto object = global_object.heap().allocate<GeneratorObject>(global_object, global_object);
+ // This is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
+ auto generating_function_proto_property = generating_function->get(global_object.vm().names.prototype).to_object(global_object);
+ if (!generating_function_proto_property)
+ return {};
+
+ auto object = global_object.heap().allocate<GeneratorObject>(global_object, global_object, *generating_function_proto_property);
object->m_generating_function = generating_function;
object->m_scope = generating_scope;
object->m_frame = move(frame);
@@ -22,21 +28,13 @@ GeneratorObject* GeneratorObject::create(GlobalObject& global_object, Value init
return object;
}
-GeneratorObject::GeneratorObject(GlobalObject& global_object)
- : Object(*global_object.object_prototype())
+GeneratorObject::GeneratorObject(GlobalObject&, Object& prototype)
+ : Object(prototype)
{
}
-void GeneratorObject::initialize(GlobalObject& global_object)
+void GeneratorObject::initialize(GlobalObject&)
{
- // FIXME: These should be on a separate Generator prototype object!
- // https://tc39.es/ecma262/#sec-generator-objects
-
- auto& vm = this->vm();
- Object::initialize(global_object);
- define_native_function(vm.names.next, next);
- define_native_function(vm.names.return_, return_);
- define_native_function(vm.names.throw_, throw_);
}
GeneratorObject::~GeneratorObject()
@@ -52,18 +50,6 @@ void GeneratorObject::visit_edges(Cell::Visitor& visitor)
visitor.visit(&m_previous_value.as_object());
}
-GeneratorObject* GeneratorObject::typed_this(VM& vm, GlobalObject& global_object)
-{
- auto* this_object = vm.this_value(global_object).to_object(global_object);
- if (!this_object)
- return {};
- if (!is<GeneratorObject>(this_object)) {
- vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Generator");
- return nullptr;
- }
- return static_cast<GeneratorObject*>(this_object);
-}
-
Value GeneratorObject::next_impl(VM& vm, GlobalObject& global_object, Optional<Value> value_to_throw)
{
auto bytecode_interpreter = Bytecode::Interpreter::current();
@@ -138,29 +124,4 @@ Value GeneratorObject::next_impl(VM& vm, GlobalObject& global_object, Optional<V
return result;
}
-JS_DEFINE_NATIVE_FUNCTION(GeneratorObject::next)
-{
- auto object = typed_this(vm, global_object);
- if (!object)
- return {};
- return object->next_impl(vm, global_object, {});
-}
-
-JS_DEFINE_NATIVE_FUNCTION(GeneratorObject::return_)
-{
- auto object = typed_this(vm, global_object);
- if (!object)
- return {};
- object->m_done = true;
- return object->next_impl(vm, global_object, {});
-}
-
-JS_DEFINE_NATIVE_FUNCTION(GeneratorObject::throw_)
-{
- auto object = typed_this(vm, global_object);
- if (!object)
- return {};
- return object->next_impl(vm, global_object, vm.argument(0));
-}
-
}
diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObject.h b/Userland/Libraries/LibJS/Runtime/GeneratorObject.h
index e25d8e8198..d8d5f90200 100644
--- a/Userland/Libraries/LibJS/Runtime/GeneratorObject.h
+++ b/Userland/Libraries/LibJS/Runtime/GeneratorObject.h
@@ -16,20 +16,15 @@ class GeneratorObject final : public Object {
public:
static GeneratorObject* create(GlobalObject&, Value, ScriptFunction*, ScopeObject*, Bytecode::RegisterWindow);
- explicit GeneratorObject(GlobalObject&);
+ GeneratorObject(GlobalObject&, Object& prototype);
virtual void initialize(GlobalObject&) override;
virtual ~GeneratorObject() override;
void visit_edges(Cell::Visitor&) override;
- static GeneratorObject* typed_this(VM&, GlobalObject&);
-
-private:
- JS_DECLARE_NATIVE_FUNCTION(next);
- JS_DECLARE_NATIVE_FUNCTION(return_);
- JS_DECLARE_NATIVE_FUNCTION(throw_);
-
Value next_impl(VM&, GlobalObject&, Optional<Value> value_to_throw);
+ void set_done() { m_done = true; }
+private:
ScopeObject* m_scope { nullptr };
ScriptFunction* m_generating_function { nullptr };
Value m_previous_value;
diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObjectPrototype.cpp b/Userland/Libraries/LibJS/Runtime/GeneratorObjectPrototype.cpp
new file mode 100644
index 0000000000..48141a0751
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/GeneratorObjectPrototype.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Bytecode/Interpreter.h>
+#include <LibJS/Runtime/GeneratorObject.h>
+#include <LibJS/Runtime/GeneratorObjectPrototype.h>
+
+namespace JS {
+
+static GeneratorObject* typed_this(VM& vm, GlobalObject& global_object)
+{
+ auto* this_object = vm.this_value(global_object).to_object(global_object);
+ if (!this_object)
+ return {};
+ if (!is<GeneratorObject>(this_object)) {
+ vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Generator");
+ return nullptr;
+ }
+ return static_cast<GeneratorObject*>(this_object);
+}
+
+GeneratorObjectPrototype::GeneratorObjectPrototype(GlobalObject& global_object)
+ : Object(*global_object.iterator_prototype())
+{
+}
+
+void GeneratorObjectPrototype::initialize(GlobalObject& global_object)
+{
+ auto& vm = this->vm();
+ Object::initialize(global_object);
+ u8 attr = Attribute::Writable | Attribute::Configurable;
+ define_native_function(vm.names.next, next, 1, attr);
+ define_native_function(vm.names.return_, return_, 1, attr);
+ define_native_function(vm.names.throw_, throw_, 1, attr);
+
+ // 27.5.1.5 Generator.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-generator.prototype-@@tostringtag
+ define_property(vm.well_known_symbol_to_string_tag(), js_string(vm, "Generator"), Attribute::Configurable);
+}
+
+GeneratorObjectPrototype::~GeneratorObjectPrototype()
+{
+}
+
+// 27.5.1.2 Generator.prototype.next ( value ), https://tc39.es/ecma262/#sec-generator.prototype.next
+JS_DEFINE_NATIVE_FUNCTION(GeneratorObjectPrototype::next)
+{
+ auto generator_object = typed_this(vm, global_object);
+ if (!generator_object)
+ return {};
+ return generator_object->next_impl(vm, global_object, {});
+}
+
+// 27.5.1.3 Generator.prototype.next ( value ), https://tc39.es/ecma262/#sec-generator.prototype.return
+JS_DEFINE_NATIVE_FUNCTION(GeneratorObjectPrototype::return_)
+{
+ auto generator_object = typed_this(vm, global_object);
+ if (!generator_object)
+ return {};
+ generator_object->set_done();
+ return generator_object->next_impl(vm, global_object, {});
+}
+
+// 27.5.1.4 Generator.prototype.next ( value ), https://tc39.es/ecma262/#sec-generator.prototype.throw
+JS_DEFINE_NATIVE_FUNCTION(GeneratorObjectPrototype::throw_)
+{
+ auto generator_object = typed_this(vm, global_object);
+ if (!generator_object)
+ return {};
+ return generator_object->next_impl(vm, global_object, vm.argument(0));
+}
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorObjectPrototype.h b/Userland/Libraries/LibJS/Runtime/GeneratorObjectPrototype.h
new file mode 100644
index 0000000000..4388612f90
--- /dev/null
+++ b/Userland/Libraries/LibJS/Runtime/GeneratorObjectPrototype.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/GlobalObject.h>
+
+namespace JS {
+
+// 27.5.1 %GeneratorFunction.prototype.prototype%, https://tc39.es/ecma262/#sec-properties-of-generator-prototype
+class GeneratorObjectPrototype final : public Object {
+ JS_OBJECT(GeneratorObjectPrototype, Object);
+
+public:
+ explicit GeneratorObjectPrototype(GlobalObject&);
+ virtual void initialize(GlobalObject&) override;
+ virtual ~GeneratorObjectPrototype() override;
+
+private:
+ JS_DECLARE_NATIVE_FUNCTION(next);
+ JS_DECLARE_NATIVE_FUNCTION(return_);
+ JS_DECLARE_NATIVE_FUNCTION(throw_);
+};
+
+}
diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
index 59cb867fc2..efb0c5ec77 100644
--- a/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
+++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.cpp
@@ -37,6 +37,9 @@
#include <LibJS/Runtime/FinalizationRegistryPrototype.h>
#include <LibJS/Runtime/FunctionConstructor.h>
#include <LibJS/Runtime/FunctionPrototype.h>
+#include <LibJS/Runtime/GeneratorFunctionConstructor.h>
+#include <LibJS/Runtime/GeneratorFunctionPrototype.h>
+#include <LibJS/Runtime/GeneratorObjectPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorPrototype.h>
#include <LibJS/Runtime/JSONObject.h>
@@ -110,18 +113,23 @@ void GlobalObject::initialize_global_object()
// This must be initialized before allocating AggregateErrorPrototype, which uses ErrorPrototype as its prototype.
m_error_prototype = heap().allocate<ErrorPrototype>(*this, *this);
-#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
- if (!m_##snake_name##_prototype) \
- m_##snake_name##_prototype = heap().allocate<PrototypeName>(*this, *this);
- JS_ENUMERATE_BUILTIN_TYPES
-#undef __JS_ENUMERATE
-
#define __JS_ENUMERATE(ClassName, snake_name) \
if (!m_##snake_name##_prototype) \
m_##snake_name##_prototype = heap().allocate<ClassName##Prototype>(*this, *this);
JS_ENUMERATE_ITERATOR_PROTOTYPES
#undef __JS_ENUMERATE
+ // %GeneratorFunction.prototype.prototype% must be initialized separately as it has no
+ // companion constructor
+ m_generator_object_prototype = heap().allocate<GeneratorObjectPrototype>(*this, *this);
+ m_generator_object_prototype->define_property(vm.names.constructor, m_generator_function_constructor, Attribute::Configurable);
+
+#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
+ if (!m_##snake_name##_prototype) \
+ m_##snake_name##_prototype = heap().allocate<PrototypeName>(*this, *this);
+ JS_ENUMERATE_BUILTIN_TYPES
+#undef __JS_ENUMERATE
+
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(vm.names.gc, gc, 0, attr);
define_native_function(vm.names.isNaN, is_nan, 1, attr);
@@ -179,6 +187,11 @@ void GlobalObject::initialize_global_object()
JS_ENUMERATE_NATIVE_ERRORS
JS_ENUMERATE_TYPED_ARRAYS
#undef __JS_ENUMERATE
+
+ // The generator constructor cannot be initialized with add_constructor as it has no global binding
+ m_generator_function_constructor = heap().allocate<GeneratorFunctionConstructor>(*this, *this);
+ // 27.3.3.1 GeneratorFunction.prototype.constructor, https://tc39.es/ecma262/#sec-generatorfunction.prototype.constructor
+ m_generator_function_prototype->define_property(vm.names.constructor, m_generator_function_constructor, Attribute::Configurable);
}
GlobalObject::~GlobalObject()
@@ -193,6 +206,7 @@ void GlobalObject::visit_edges(Visitor& visitor)
visitor.visit(m_new_object_shape);
visitor.visit(m_new_script_function_prototype_object_shape);
visitor.visit(m_proxy_constructor);
+ visitor.visit(m_generator_object_prototype);
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
visitor.visit(m_##snake_name##_constructor); \
diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.h b/Userland/Libraries/LibJS/Runtime/GlobalObject.h
index 16c766fdca..76ceca24ac 100644
--- a/Userland/Libraries/LibJS/Runtime/GlobalObject.h
+++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.h
@@ -37,6 +37,9 @@ public:
// Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype
ProxyConstructor* proxy_constructor() { return m_proxy_constructor; }
+ // Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct constructor
+ GeneratorObjectPrototype* generator_object_prototype() { return m_generator_object_prototype; }
+
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
ConstructorName* snake_name##_constructor() { return m_##snake_name##_constructor; } \
Object* snake_name##_prototype() { return m_##snake_name##_prototype; }
@@ -81,6 +84,9 @@ private:
// Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct prototype
ProxyConstructor* m_proxy_constructor { nullptr };
+ // Not included in JS_ENUMERATE_NATIVE_OBJECTS due to missing distinct constructor
+ GeneratorObjectPrototype* m_generator_object_prototype { nullptr };
+
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
ConstructorName* m_##snake_name##_constructor { nullptr }; \
Object* m_##snake_name##_prototype { nullptr };
diff --git a/Userland/Libraries/LibJS/Runtime/ScriptFunction.cpp b/Userland/Libraries/LibJS/Runtime/ScriptFunction.cpp
index f90304190b..6ac8ac8b75 100644
--- a/Userland/Libraries/LibJS/Runtime/ScriptFunction.cpp
+++ b/Userland/Libraries/LibJS/Runtime/ScriptFunction.cpp
@@ -15,6 +15,7 @@
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GeneratorObject.h>
+#include <LibJS/Runtime/GeneratorObjectPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/ScriptFunction.h>
@@ -36,7 +37,16 @@ static ScriptFunction* typed_this(VM& vm, GlobalObject& global_object)
ScriptFunction* ScriptFunction::create(GlobalObject& global_object, const FlyString& name, const Statement& body, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, ScopeObject* parent_scope, FunctionKind kind, bool is_strict, bool is_arrow_function)
{
- return global_object.heap().allocate<ScriptFunction>(global_object, global_object, name, body, move(parameters), m_function_length, parent_scope, *global_object.function_prototype(), kind, is_strict, is_arrow_function);
+ Object* prototype = nullptr;
+ switch (kind) {
+ case FunctionKind::Regular:
+ prototype = global_object.function_prototype();
+ break;
+ case FunctionKind::Generator:
+ prototype = global_object.generator_function_prototype();
+ break;
+ }
+ return global_object.heap().allocate<ScriptFunction>(global_object, global_object, name, body, move(parameters), m_function_length, parent_scope, *prototype, kind, is_strict, is_arrow_function);
}
ScriptFunction::ScriptFunction(GlobalObject& global_object, const FlyString& name, const Statement& body, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, ScopeObject* parent_scope, Object& prototype, FunctionKind kind, bool is_strict, bool is_arrow_function)
@@ -57,8 +67,16 @@ void ScriptFunction::initialize(GlobalObject& global_object)
auto& vm = this->vm();
Function::initialize(global_object);
if (!m_is_arrow_function) {
- Object* prototype = vm.heap().allocate<Object>(global_object, *global_object.new_script_function_prototype_object_shape());
- prototype->define_property(vm.names.constructor, this, Attribute::Writable | Attribute::Configurable);
+ auto* prototype = vm.heap().allocate<Object>(global_object, *global_object.new_script_function_prototype_object_shape());
+ switch (m_kind) {
+ case FunctionKind::Regular:
+ prototype->define_property(vm.names.constructor, this, Attribute::Writable | Attribute::Configurable);
+ break;
+ case FunctionKind::Generator:
+ // prototype is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
+ prototype->set_prototype(global_object.generator_object_prototype());
+ break;
+ }
define_property(vm.names.prototype, prototype, Attribute::Writable);
}
define_native_property(vm.names.length, length_getter, {}, Attribute::Configurable);
@@ -205,7 +223,7 @@ Value ScriptFunction::call()
Value ScriptFunction::construct(Function&)
{
- if (m_is_arrow_function) {
+ if (m_is_arrow_function || m_kind == FunctionKind::Generator) {
vm().throw_exception<TypeError>(global_object(), ErrorType::NotAConstructor, m_name);
return {};
}