Browse Source

LibJS: Allow GeneratorObject to be subclassed

In the Iterator Helpers proposal, we must create a generator object with
additional internal slots and behavior differences.

GeneratorObject is currently implemented assuming it wraps around an
ECMAScriptFunctionObject with generated bytecode. In this proposal, we
instead have "Abstract Closure" blocks. So this marks the `execute`
method as virtual, to allow the future subclass to essentially just
invoke those closures.

We will also require mutable access to the [[GeneratorState]] internal
slot.
Timothy Flynn 2 years ago
parent
commit
566a8dfd93

+ 4 - 4
Userland/Libraries/LibJS/Print.cpp

@@ -421,15 +421,15 @@ ErrorOr<void> print_shadow_realm(JS::PrintContext& print_context, JS::ShadowReal
     return {};
     return {};
 }
 }
 
 
-ErrorOr<void> print_generator(JS::PrintContext& print_context, JS::GeneratorObject const&, HashTable<JS::Object*>&)
+ErrorOr<void> print_generator(JS::PrintContext& print_context, JS::GeneratorObject const& generator, HashTable<JS::Object*>&)
 {
 {
-    TRY(print_type(print_context, "Generator"sv));
+    TRY(print_type(print_context, generator.class_name()));
     return {};
     return {};
 }
 }
 
 
-ErrorOr<void> print_async_generator(JS::PrintContext& print_context, JS::AsyncGenerator const&, HashTable<JS::Object*>&)
+ErrorOr<void> print_async_generator(JS::PrintContext& print_context, JS::AsyncGenerator const& generator, HashTable<JS::Object*>&)
 {
 {
-    TRY(print_type(print_context, "AsyncGenerator"sv));
+    TRY(print_type(print_context, generator.class_name()));
     return {};
     return {};
 }
 }
 
 

+ 2 - 1
Userland/Libraries/LibJS/Runtime/GeneratorObject.cpp

@@ -35,9 +35,10 @@ ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> GeneratorObject::create(Realm&
     return object;
     return object;
 }
 }
 
 
-GeneratorObject::GeneratorObject(Realm&, Object& prototype, ExecutionContext context)
+GeneratorObject::GeneratorObject(Realm&, Object& prototype, ExecutionContext context, Optional<StringView> generator_brand)
     : Object(ConstructWithPrototypeTag::Tag, prototype)
     : Object(ConstructWithPrototypeTag::Tag, prototype)
     , m_execution_context(move(context))
     , m_execution_context(move(context))
+    , m_generator_brand(move(generator_brand))
 {
 {
 }
 }
 
 

+ 8 - 5
Userland/Libraries/LibJS/Runtime/GeneratorObject.h

@@ -12,7 +12,7 @@
 
 
 namespace JS {
 namespace JS {
 
 
-class GeneratorObject final : public Object {
+class GeneratorObject : public Object {
     JS_OBJECT(GeneratorObject, Object);
     JS_OBJECT(GeneratorObject, Object);
 
 
 public:
 public:
@@ -23,19 +23,22 @@ public:
     ThrowCompletionOr<Value> resume(VM&, Value value, Optional<StringView> const& generator_brand);
     ThrowCompletionOr<Value> resume(VM&, Value value, Optional<StringView> const& generator_brand);
     ThrowCompletionOr<Value> resume_abrupt(VM&, JS::Completion abrupt_completion, Optional<StringView> const& generator_brand);
     ThrowCompletionOr<Value> resume_abrupt(VM&, JS::Completion abrupt_completion, Optional<StringView> const& generator_brand);
 
 
-private:
-    GeneratorObject(Realm&, Object& prototype, ExecutionContext);
-
     enum class GeneratorState {
     enum class GeneratorState {
         SuspendedStart,
         SuspendedStart,
         SuspendedYield,
         SuspendedYield,
         Executing,
         Executing,
         Completed,
         Completed,
     };
     };
+    GeneratorState generator_state() const { return m_generator_state; }
+    void set_generator_state(GeneratorState generator_state) { m_generator_state = generator_state; }
+
+protected:
+    GeneratorObject(Realm&, Object& prototype, ExecutionContext, Optional<StringView> generator_brand = {});
 
 
     ThrowCompletionOr<GeneratorState> validate(VM&, Optional<StringView> const& generator_brand);
     ThrowCompletionOr<GeneratorState> validate(VM&, Optional<StringView> const& generator_brand);
-    ThrowCompletionOr<Value> execute(VM&, JS::Completion const& completion);
+    virtual ThrowCompletionOr<Value> execute(VM&, JS::Completion const& completion);
 
 
+private:
     ExecutionContext m_execution_context;
     ExecutionContext m_execution_context;
     GCPtr<ECMAScriptFunctionObject> m_generating_function;
     GCPtr<ECMAScriptFunctionObject> m_generating_function;
     Value m_previous_value;
     Value m_previous_value;