diff options
author | Matthew Olsson <matthewcolsson@gmail.com> | 2021-06-15 00:04:08 -0700 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-06-19 00:04:57 +0100 |
commit | 22b17219ff85f666f2ddc81347be8d6117740af6 (patch) | |
tree | a7aa282903bb27c01d027b96b31c23ff5f01ef37 /Userland | |
parent | b205c9814a34210b42b582ed36eb2ede008ebfa6 (diff) | |
download | serenity-22b17219ff85f666f2ddc81347be8d6117740af6.zip |
LibJS: Add the remaining generator objects
- %GeneratorFunction%
- %GeneratorFunction.prototype%
- %GeneratorFunction.prototype.prototype%
- %Generator%.prototype
Diffstat (limited to 'Userland')
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 {}; } |