1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 13:47:35 +00:00

LibJS: Parse async generator functions

This commit is contained in:
davidot 2021-11-15 01:53:24 +01:00 committed by Linus Groh
parent 5d0f666f22
commit 0982a73d1d
13 changed files with 270 additions and 40 deletions

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2021, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/AsyncGeneratorFunctionConstructor.h>
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
#include <LibJS/Runtime/FunctionConstructor.h>
#include <LibJS/Runtime/FunctionObject.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
AsyncGeneratorFunctionConstructor::AsyncGeneratorFunctionConstructor(GlobalObject& global_object)
: NativeFunction(vm().names.AsyncGeneratorFunction.as_string(), *global_object.function_prototype())
{
}
void AsyncGeneratorFunctionConstructor::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
NativeFunction::initialize(global_object);
// 27.4.2.2 AsyncGeneratorFunction.prototype, https://tc39.es/ecma262/#sec-asyncgeneratorfunction-prototype
define_direct_property(vm.names.prototype, global_object.async_generator_function_prototype(), 0);
// 27.4.2.1 AsyncGeneratorFunction.length, https://tc39.es/ecma262/#sec-asyncgeneratorfunction-length
define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
// 27.4.2.2 AsyncGeneratorFunction.prototype, https://tc39.es/ecma262/#sec-asyncgeneratorfunction-prototype
define_direct_property(vm.names.prototype, global_object.async_generator_function_prototype(), 0);
}
// 27.4.1.1 AsyncGeneratorFunction ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-asyncgeneratorfunction
ThrowCompletionOr<Value> AsyncGeneratorFunctionConstructor::call()
{
return TRY(construct(*this));
}
// 27.4.1.1 AsyncGeneratorFunction ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-asyncgeneratorfunction
ThrowCompletionOr<Object*> AsyncGeneratorFunctionConstructor::construct(FunctionObject& new_target)
{
auto& vm = this->vm();
auto function = TRY(FunctionConstructor::create_dynamic_function_node(global_object(), new_target, FunctionKind::AsyncGenerator));
OwnPtr<Interpreter> local_interpreter;
Interpreter* interpreter = vm.interpreter_if_exists();
if (!interpreter) {
local_interpreter = Interpreter::create_with_existing_realm(*realm());
interpreter = local_interpreter.ptr();
}
VM::InterpreterExecutionScope scope(*interpreter);
auto result = function->execute(*interpreter, global_object());
if (auto* exception = vm.exception())
return throw_completion(exception->value());
VERIFY(result.is_object() && is<ECMAScriptFunctionObject>(result.as_object()));
return &result.as_object();
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2021, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Runtime/NativeFunction.h>
namespace JS {
class AsyncGeneratorFunctionConstructor final : public NativeFunction {
JS_OBJECT(AsyncGeneratorFunctionConstructor, NativeFunction);
public:
explicit AsyncGeneratorFunctionConstructor(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~AsyncGeneratorFunctionConstructor() override = default;
virtual ThrowCompletionOr<Value> call() override;
virtual ThrowCompletionOr<Object*> construct(FunctionObject& new_target) override;
private:
virtual bool has_constructor() const override { return true; }
};
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2021, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AsyncGeneratorFunctionConstructor.h>
#include <LibJS/Runtime/AsyncGeneratorFunctionPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
AsyncGeneratorFunctionPrototype::AsyncGeneratorFunctionPrototype(GlobalObject& global_object)
: PrototypeObject(*global_object.function_prototype())
{
}
void AsyncGeneratorFunctionPrototype::initialize(GlobalObject& global_object)
{
auto& vm = this->vm();
Object::initialize(global_object);
// The constructor cannot be set at this point since it has not been initialized.
// 27.4.3.2 AsyncGeneratorFunction.prototype.prototype, https://tc39.es/ecma262/#sec-asyncgeneratorfunction-prototype-prototype
// FIXME: AsyncGenerator does not exist yet.
// define_direct_property(vm.names.prototype, global_object.async_generator_prototype(), Attribute::Configurable);
// 27.4.3.3 AsyncGeneratorFunction.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-asyncgeneratorfunction-prototype-tostringtag
define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, vm.names.AsyncGeneratorFunction.as_string()), Attribute::Configurable);
}
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2021, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Runtime/PrototypeObject.h>
namespace JS {
class AsyncGeneratorFunctionPrototype final : public PrototypeObject<AsyncGeneratorFunctionPrototype, AsyncGeneratorFunction> {
JS_PROTOTYPE_OBJECT(AsyncGeneratorFunctionPrototype, AsyncGeneratorFunction, AsyncGeneratorFunction);
public:
explicit AsyncGeneratorFunctionPrototype(GlobalObject&);
virtual void initialize(GlobalObject&) override;
virtual ~AsyncGeneratorFunctionPrototype() override = default;
};
}

View file

@ -41,6 +41,9 @@ ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_
case FunctionKind::Async:
prototype = global_object.async_function_prototype();
break;
case FunctionKind::AsyncGenerator:
prototype = global_object.async_generator_function_prototype();
break;
}
return global_object.heap().allocate<ECMAScriptFunctionObject>(global_object, move(name), ecmascript_code, move(parameters), m_function_length, parent_scope, private_scope, *prototype, kind, is_strict, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function);
}
@ -106,6 +109,9 @@ void ECMAScriptFunctionObject::initialize(GlobalObject& global_object)
break;
case FunctionKind::Async:
break;
case FunctionKind::AsyncGenerator:
// FIXME: Add the AsyncGeneratorObject and set it as prototype.
break;
}
define_direct_property(vm.names.prototype, prototype, Attribute::Writable);
}
@ -750,6 +756,9 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
auto& vm = this->vm();
auto* bytecode_interpreter = Bytecode::Interpreter::current();
if (m_kind == FunctionKind::AsyncGenerator)
return vm.throw_completion<InternalError>(global_object(), ErrorType::NotImplemented, "Async Generator function execution");
if (bytecode_interpreter) {
// FIXME: pass something to evaluate default arguments with
TRY(function_declaration_instantiation(nullptr));

View file

@ -53,8 +53,8 @@ ThrowCompletionOr<RefPtr<FunctionExpression>> FunctionConstructor::create_dynami
parameters_source = parameters_builder.build();
body_source = TRY(vm.argument(vm.argument_count() - 1).to_string(global_object));
}
auto is_generator = kind == FunctionKind::Generator;
auto is_async = kind == FunctionKind::Async;
auto is_generator = kind == FunctionKind::Generator || kind == FunctionKind::AsyncGenerator;
auto is_async = kind == FunctionKind::Async || kind == FunctionKind::AsyncGenerator;
auto source = String::formatted("{}function{} anonymous({}\n) {{\n{}\n}}", is_async ? "async " : "", is_generator ? "*" : "", parameters_source, body_source);
auto parser = Parser(Lexer(source));
auto function = parser.parse_function_node<FunctionExpression>();

View file

@ -12,6 +12,7 @@ enum class FunctionKind {
Generator,
Regular,
Async,
AsyncGenerator
};
}

View file

@ -22,6 +22,8 @@
#include <LibJS/Runtime/ArrayPrototype.h>
#include <LibJS/Runtime/AsyncFunctionConstructor.h>
#include <LibJS/Runtime/AsyncFunctionPrototype.h>
#include <LibJS/Runtime/AsyncGeneratorFunctionConstructor.h>
#include <LibJS/Runtime/AsyncGeneratorFunctionPrototype.h>
#include <LibJS/Runtime/AtomicsObject.h>
#include <LibJS/Runtime/BigIntConstructor.h>
#include <LibJS/Runtime/BigIntPrototype.h>
@ -273,6 +275,11 @@ void GlobalObject::initialize_global_object()
// 27.3.3.1 GeneratorFunction.prototype.constructor, https://tc39.es/ecma262/#sec-generatorfunction.prototype.constructor
m_generator_function_prototype->define_direct_property(vm.names.constructor, m_generator_function_constructor, Attribute::Configurable);
// The async generator constructor cannot be initialized with add_constructor as it has no global binding
m_async_generator_function_constructor = heap().allocate<AsyncGeneratorFunctionConstructor>(*this, *this);
// 27.4.3.1 AsyncGeneratorFunction.prototype.constructor, https://tc39.es/ecma262/#sec-asyncgeneratorfunction-prototype-constructor
m_async_generator_function_prototype->define_direct_property(vm.names.constructor, m_async_generator_function_constructor, Attribute::Configurable);
m_array_prototype_values_function = &m_array_prototype->get_without_side_effects(vm.names.values).as_function();
m_eval_function = &get_without_side_effects(vm.names.eval).as_function();
}