mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibJS: Parse async generator functions
This commit is contained in:
parent
5d0f666f22
commit
0982a73d1d
Notes:
sideshowbarker
2024-07-18 00:53:17 +09:00
Author: https://github.com/davidot Commit: https://github.com/SerenityOS/serenity/commit/0982a73d1d8 Pull-request: https://github.com/SerenityOS/serenity/pull/10926 Reviewed-by: https://github.com/linusg ✅
13 changed files with 270 additions and 40 deletions
|
@ -1938,7 +1938,9 @@ void BindingPattern::dump(int indent) const
|
|||
void FunctionNode::dump(int indent, String const& class_name) const
|
||||
{
|
||||
print_indent(indent);
|
||||
outln("{}{}{} '{}'", class_name, m_kind == FunctionKind::Async ? " async" : "", m_kind == FunctionKind::Generator ? "*" : "", name());
|
||||
auto is_async = m_kind == FunctionKind::Async || m_kind == FunctionKind::AsyncGenerator;
|
||||
auto is_generator = m_kind == FunctionKind::Generator || m_kind == FunctionKind::AsyncGenerator;
|
||||
outln("{}{}{} '{}'", class_name, is_async ? " async" : "", is_generator ? "*" : "", name());
|
||||
if (m_contains_direct_call_to_eval) {
|
||||
print_indent(indent + 1);
|
||||
outln("\033[31;1m(direct eval)\033[0m");
|
||||
|
|
|
@ -41,6 +41,8 @@ set(SOURCES
|
|||
Runtime/AsyncFunctionConstructor.cpp
|
||||
Runtime/AsyncFunctionDriverWrapper.cpp
|
||||
Runtime/AsyncFunctionPrototype.cpp
|
||||
Runtime/AsyncGeneratorFunctionConstructor.cpp
|
||||
Runtime/AsyncGeneratorFunctionPrototype.cpp
|
||||
Runtime/AtomicsObject.cpp
|
||||
Runtime/BigInt.cpp
|
||||
Runtime/BigIntConstructor.cpp
|
||||
|
|
|
@ -13,30 +13,31 @@
|
|||
JS::ThrowCompletionOr<JS::Value> name([[maybe_unused]] JS::VM& vm, [[maybe_unused]] JS::GlobalObject& global_object)
|
||||
|
||||
// NOTE: Proxy is not included here as it doesn't have a prototype - m_proxy_constructor is initialized separately.
|
||||
#define JS_ENUMERATE_NATIVE_OBJECTS_EXCLUDING_TEMPLATES \
|
||||
__JS_ENUMERATE(AggregateError, aggregate_error, AggregateErrorPrototype, AggregateErrorConstructor, void) \
|
||||
__JS_ENUMERATE(Array, array, ArrayPrototype, ArrayConstructor, void) \
|
||||
__JS_ENUMERATE(ArrayBuffer, array_buffer, ArrayBufferPrototype, ArrayBufferConstructor, void) \
|
||||
__JS_ENUMERATE(AsyncFunction, async_function, AsyncFunctionPrototype, AsyncFunctionConstructor, void) \
|
||||
__JS_ENUMERATE(BigIntObject, bigint, BigIntPrototype, BigIntConstructor, void) \
|
||||
__JS_ENUMERATE(BooleanObject, boolean, BooleanPrototype, BooleanConstructor, void) \
|
||||
__JS_ENUMERATE(DataView, data_view, DataViewPrototype, DataViewConstructor, void) \
|
||||
__JS_ENUMERATE(Date, date, DatePrototype, DateConstructor, void) \
|
||||
__JS_ENUMERATE(Error, error, ErrorPrototype, ErrorConstructor, void) \
|
||||
__JS_ENUMERATE(FinalizationRegistry, finalization_registry, FinalizationRegistryPrototype, FinalizationRegistryConstructor, void) \
|
||||
__JS_ENUMERATE(FunctionObject, 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) \
|
||||
__JS_ENUMERATE(Promise, promise, PromisePrototype, PromiseConstructor, void) \
|
||||
__JS_ENUMERATE(RegExpObject, regexp, RegExpPrototype, RegExpConstructor, void) \
|
||||
__JS_ENUMERATE(Set, set, SetPrototype, SetConstructor, void) \
|
||||
__JS_ENUMERATE(ShadowRealm, shadow_realm, ShadowRealmPrototype, ShadowRealmConstructor, void) \
|
||||
__JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor, void) \
|
||||
__JS_ENUMERATE(SymbolObject, symbol, SymbolPrototype, SymbolConstructor, void) \
|
||||
__JS_ENUMERATE(WeakMap, weak_map, WeakMapPrototype, WeakMapConstructor, void) \
|
||||
__JS_ENUMERATE(WeakRef, weak_ref, WeakRefPrototype, WeakRefConstructor, void) \
|
||||
#define JS_ENUMERATE_NATIVE_OBJECTS_EXCLUDING_TEMPLATES \
|
||||
__JS_ENUMERATE(AggregateError, aggregate_error, AggregateErrorPrototype, AggregateErrorConstructor, void) \
|
||||
__JS_ENUMERATE(Array, array, ArrayPrototype, ArrayConstructor, void) \
|
||||
__JS_ENUMERATE(ArrayBuffer, array_buffer, ArrayBufferPrototype, ArrayBufferConstructor, void) \
|
||||
__JS_ENUMERATE(AsyncFunction, async_function, AsyncFunctionPrototype, AsyncFunctionConstructor, void) \
|
||||
__JS_ENUMERATE(AsyncGeneratorFunction, async_generator_function, AsyncGeneratorFunctionPrototype, AsyncGeneratorFunctionConstructor, void) \
|
||||
__JS_ENUMERATE(BigIntObject, bigint, BigIntPrototype, BigIntConstructor, void) \
|
||||
__JS_ENUMERATE(BooleanObject, boolean, BooleanPrototype, BooleanConstructor, void) \
|
||||
__JS_ENUMERATE(DataView, data_view, DataViewPrototype, DataViewConstructor, void) \
|
||||
__JS_ENUMERATE(Date, date, DatePrototype, DateConstructor, void) \
|
||||
__JS_ENUMERATE(Error, error, ErrorPrototype, ErrorConstructor, void) \
|
||||
__JS_ENUMERATE(FinalizationRegistry, finalization_registry, FinalizationRegistryPrototype, FinalizationRegistryConstructor, void) \
|
||||
__JS_ENUMERATE(FunctionObject, 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) \
|
||||
__JS_ENUMERATE(Promise, promise, PromisePrototype, PromiseConstructor, void) \
|
||||
__JS_ENUMERATE(RegExpObject, regexp, RegExpPrototype, RegExpConstructor, void) \
|
||||
__JS_ENUMERATE(Set, set, SetPrototype, SetConstructor, void) \
|
||||
__JS_ENUMERATE(ShadowRealm, shadow_realm, ShadowRealmPrototype, ShadowRealmConstructor, void) \
|
||||
__JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor, void) \
|
||||
__JS_ENUMERATE(SymbolObject, symbol, SymbolPrototype, SymbolConstructor, void) \
|
||||
__JS_ENUMERATE(WeakMap, weak_map, WeakMapPrototype, WeakMapConstructor, void) \
|
||||
__JS_ENUMERATE(WeakRef, weak_ref, WeakRefPrototype, WeakRefConstructor, void) \
|
||||
__JS_ENUMERATE(WeakSet, weak_set, WeakSetPrototype, WeakSetConstructor, void)
|
||||
|
||||
#define JS_ENUMERATE_NATIVE_OBJECTS \
|
||||
|
|
|
@ -1483,18 +1483,23 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression()
|
|||
|
||||
auto type = m_state.current_token.type();
|
||||
|
||||
if (match(TokenType::Async)) {
|
||||
auto lookahead_token = next_token();
|
||||
|
||||
if (lookahead_token.type() != TokenType::ParenOpen && !lookahead_token.trivia_contains_line_terminator()) {
|
||||
consume(TokenType::Async);
|
||||
function_kind = FunctionKind::Async;
|
||||
}
|
||||
}
|
||||
if (match(TokenType::Asterisk)) {
|
||||
consume();
|
||||
property_type = ObjectProperty::Type::KeyValue;
|
||||
property_name = parse_property_key();
|
||||
function_kind = FunctionKind::Generator;
|
||||
VERIFY(function_kind == FunctionKind::Regular || function_kind == FunctionKind::Async);
|
||||
function_kind = function_kind == FunctionKind::Regular ? FunctionKind::Generator : FunctionKind::AsyncGenerator;
|
||||
} else if (match_identifier()) {
|
||||
auto identifier = consume();
|
||||
if (identifier.original_value() == "async" && match_property_key() && !m_state.current_token.trivia_contains_line_terminator()) {
|
||||
property_type = ObjectProperty::Type::KeyValue;
|
||||
property_name = parse_property_key();
|
||||
function_kind = FunctionKind::Async;
|
||||
} else if (identifier.original_value() == "get"sv && match_property_key()) {
|
||||
if (identifier.original_value() == "get"sv && match_property_key()) {
|
||||
property_type = ObjectProperty::Type::Getter;
|
||||
property_name = parse_property_key();
|
||||
} else if (identifier.original_value() == "set"sv && match_property_key()) {
|
||||
|
@ -1531,9 +1536,9 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression()
|
|||
parse_options |= FunctionNodeParseOptions::IsGetterFunction;
|
||||
if (property_type == ObjectProperty::Type::Setter)
|
||||
parse_options |= FunctionNodeParseOptions::IsSetterFunction;
|
||||
if (function_kind == FunctionKind::Generator)
|
||||
if (function_kind == FunctionKind::Generator || function_kind == FunctionKind::AsyncGenerator)
|
||||
parse_options |= FunctionNodeParseOptions::IsGeneratorFunction;
|
||||
if (function_kind == FunctionKind::Async)
|
||||
if (function_kind == FunctionKind::Async || function_kind == FunctionKind::AsyncGenerator)
|
||||
parse_options |= FunctionNodeParseOptions::IsAsyncFunction;
|
||||
auto function = parse_function_node<FunctionExpression>(parse_options);
|
||||
properties.append(create_ast_node<ObjectProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, *property_name, function, property_type, true));
|
||||
|
@ -2278,12 +2283,13 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
|
|||
TemporaryChange break_context_rollback(m_state.in_break_context, false);
|
||||
TemporaryChange continue_context_rollback(m_state.in_continue_context, false);
|
||||
TemporaryChange class_field_initializer_rollback(m_state.in_class_field_initializer, false);
|
||||
TemporaryChange class_static_initializer_rollback(m_state.in_class_static_init_block, false);
|
||||
TemporaryChange might_need_arguments_object_rollback(m_state.function_might_need_arguments_object, false);
|
||||
|
||||
constexpr auto is_function_expression = IsSame<FunctionNodeType, FunctionExpression>;
|
||||
FunctionKind function_kind;
|
||||
if ((parse_options & FunctionNodeParseOptions::IsGeneratorFunction) != 0 && (parse_options & FunctionNodeParseOptions::IsAsyncFunction) != 0)
|
||||
TODO();
|
||||
function_kind = FunctionKind::AsyncGenerator;
|
||||
else if ((parse_options & FunctionNodeParseOptions::IsGeneratorFunction) != 0)
|
||||
function_kind = FunctionKind::Generator;
|
||||
else if ((parse_options & FunctionNodeParseOptions::IsAsyncFunction) != 0)
|
||||
|
@ -2298,8 +2304,8 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
|
|||
parse_options = parse_options | FunctionNodeParseOptions::IsAsyncFunction;
|
||||
}
|
||||
consume(TokenType::Function);
|
||||
if (function_kind == FunctionKind::Regular && match(TokenType::Asterisk)) {
|
||||
function_kind = FunctionKind::Generator;
|
||||
if (match(TokenType::Asterisk)) {
|
||||
function_kind = function_kind == FunctionKind::Regular ? FunctionKind::Generator : FunctionKind::AsyncGenerator;
|
||||
consume(TokenType::Asterisk);
|
||||
parse_options = parse_options | FunctionNodeParseOptions::IsGeneratorFunction;
|
||||
}
|
||||
|
@ -2311,8 +2317,8 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
|
|||
|
||||
check_identifier_name_for_assignment_validity(name);
|
||||
}
|
||||
TemporaryChange generator_change(m_state.in_generator_function_context, function_kind == FunctionKind::Generator);
|
||||
TemporaryChange async_change(m_state.in_async_function_context, function_kind == FunctionKind::Async);
|
||||
TemporaryChange generator_change(m_state.in_generator_function_context, function_kind == FunctionKind::Generator || function_kind == FunctionKind::AsyncGenerator);
|
||||
TemporaryChange async_change(m_state.in_async_function_context, function_kind == FunctionKind::Async || function_kind == FunctionKind::AsyncGenerator);
|
||||
|
||||
consume(TokenType::ParenOpen);
|
||||
i32 function_length = -1;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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; }
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -12,6 +12,7 @@ enum class FunctionKind {
|
|||
Generator,
|
||||
Regular,
|
||||
Async,
|
||||
AsyncGenerator
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
55
Userland/Libraries/LibJS/Tests/syntax/async-generators.js
Normal file
55
Userland/Libraries/LibJS/Tests/syntax/async-generators.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
describe("parsing freestanding generators", () => {
|
||||
test("simple", () => {
|
||||
expect(`async function* foo() {}`).toEval();
|
||||
expect(`async function *foo() {}`).toEval();
|
||||
expect(`async function
|
||||
*foo() {}`).toEval();
|
||||
});
|
||||
test("yield & await expression", () => {
|
||||
expect(`async function* foo() { yield; await 1; }`).toEval();
|
||||
expect(`async function* foo() { yield (yield); await (yield); }`).toEval();
|
||||
expect(`async function* foo() { yield (yield foo); yield (await foo); }`).toEval();
|
||||
|
||||
expect(`async function foo() { yield; }`).toEval();
|
||||
expect(`async function foo() { yield 3; }`).not.toEval();
|
||||
expect(`function* foo() { await 3; }`).not.toEval();
|
||||
});
|
||||
test("yield-from expression", () => {
|
||||
expect(`async function* foo() { yield *bar; }`).toEval();
|
||||
expect(`async function* foo() { yield *(yield); }`).toEval();
|
||||
expect(`async function* foo() { yield
|
||||
*bar; }`).not.toEval();
|
||||
expect(`async function foo() { yield
|
||||
*bar; }`).toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parsing object literal generator functions", () => {
|
||||
test("simple", () => {
|
||||
expect(`x = { async *foo() { } }`).toEval();
|
||||
expect(`x = { async * foo() { } }`).toEval();
|
||||
expect(`x = { async *
|
||||
foo() { } }`).toEval();
|
||||
});
|
||||
test("yield & await", () => {
|
||||
expect(`x = { async foo() { yield; await 3;} }`).toEval();
|
||||
expect(`x = { async *foo() { yield; await 3; } }`).toEval();
|
||||
expect(`x = { async *foo() { yield 42; await 3; } }`).toEval();
|
||||
expect(`x = { async *foo() { yield (yield); await (yield); } }`).toEval();
|
||||
expect(`x = { async *
|
||||
foo() { yield (yield); await 4; } }`).toEval();
|
||||
|
||||
expect(`x = { async foo() { yield 42; } }`).not.toEval();
|
||||
expect(`x = { *foo() { await 42; } }`).not.toEval();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parsing classes with generator methods", () => {
|
||||
test("simple", () => {
|
||||
expect(`class Foo { async *foo() {} }`).toEval();
|
||||
expect(`class Foo { static async *foo() {} }`).toEval();
|
||||
expect(`class Foo { async *foo() { yield; } }`).toEval();
|
||||
expect(`class Foo { async *foo() { yield 42; } }`).toEval();
|
||||
expect(`class Foo { async *constructor() { yield 42; } }`).not.toEval();
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue