LibJS: Remove C++ AST
Delete AST.cpp, AST.h, ASTDump.cpp, ScopeRecord.h, and the dead get_builtin(MemberExpression const&) from Builtins.cpp. Extract ImportEntry and ExportEntry into a new ModuleEntry.h, since they are data types used by the module system, not AST node types. Inline ModuleRequest's sorting constructor and SourceRange::filename(). Remove the dead annex_b_function_declarations field from EvalDeclarationData, which was only populated by the C++ parser.
This commit is contained in:
parent
169452f41b
commit
8ec7e7c07c
15 changed files with 112 additions and 3917 deletions
|
|
@ -1,382 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2024, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2021-2022, David Tuin <davidot@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Demangle.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/TemporaryChange.h>
|
||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Runtime/ECMAScriptFunctionObject.h>
|
||||
#include <LibJS/Runtime/Error.h>
|
||||
#include <LibJS/Runtime/GlobalEnvironment.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/SharedFunctionInstanceData.h>
|
||||
#include <LibJS/Runtime/ValueInlines.h>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace JS {
|
||||
|
||||
ASTNode::ASTNode(SourceRange source_range)
|
||||
: m_source_range(move(source_range))
|
||||
{
|
||||
}
|
||||
|
||||
ByteString ASTNode::class_name() const
|
||||
{
|
||||
// NOTE: We strip the "JS::" prefix.
|
||||
auto const* typename_ptr = typeid(*this).name();
|
||||
return demangle({ typename_ptr, strlen(typename_ptr) }).substring(4);
|
||||
}
|
||||
|
||||
Optional<Utf16String> CallExpression::expression_string() const
|
||||
{
|
||||
if (is<Identifier>(*m_callee))
|
||||
return static_cast<Identifier const&>(*m_callee).string().to_utf16_string();
|
||||
|
||||
if (is<MemberExpression>(*m_callee))
|
||||
return static_cast<MemberExpression const&>(*m_callee).to_string_approximation();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static Optional<Utf16FlyString> nullopt_or_private_identifier_description(Expression const& expression)
|
||||
{
|
||||
if (is<PrivateIdentifier>(expression))
|
||||
return static_cast<PrivateIdentifier const&>(expression).string();
|
||||
return {};
|
||||
}
|
||||
|
||||
Optional<Utf16FlyString> ClassField::private_bound_identifier() const
|
||||
{
|
||||
return nullopt_or_private_identifier_description(*m_key);
|
||||
}
|
||||
|
||||
Optional<Utf16FlyString> ClassMethod::private_bound_identifier() const
|
||||
{
|
||||
return nullopt_or_private_identifier_description(*m_key);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> ClassDeclaration::for_each_bound_identifier(ThrowCompletionOrVoidCallback<Identifier const&>&& callback) const
|
||||
{
|
||||
if (!m_class_expression->m_name)
|
||||
return {};
|
||||
|
||||
return callback(*m_class_expression->m_name);
|
||||
}
|
||||
|
||||
bool BindingPattern::contains_expression() const
|
||||
{
|
||||
for (auto& entry : entries) {
|
||||
if (entry.name.has<NonnullRefPtr<Expression const>>())
|
||||
return true;
|
||||
if (entry.initializer)
|
||||
return true;
|
||||
if (auto binding_ptr = entry.alias.get_pointer<NonnullRefPtr<BindingPattern const>>(); binding_ptr && (*binding_ptr)->contains_expression())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> BindingPattern::for_each_bound_identifier(ThrowCompletionOrVoidCallback<Identifier const&>&& callback) const
|
||||
{
|
||||
for (auto const& entry : entries) {
|
||||
auto const& alias = entry.alias;
|
||||
if (alias.has<NonnullRefPtr<Identifier const>>()) {
|
||||
TRY(callback(alias.get<NonnullRefPtr<Identifier const>>()));
|
||||
} else if (alias.has<NonnullRefPtr<BindingPattern const>>()) {
|
||||
TRY(alias.get<NonnullRefPtr<BindingPattern const>>()->for_each_bound_identifier(forward<decltype(callback)>(callback)));
|
||||
} else {
|
||||
auto const& name = entry.name;
|
||||
if (name.has<NonnullRefPtr<Identifier const>>())
|
||||
TRY(callback(name.get<NonnullRefPtr<Identifier const>>()));
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
FunctionNode::FunctionNode(RefPtr<Identifier const> name, Utf16View source_text, NonnullRefPtr<Statement const> body, NonnullRefPtr<FunctionParameters const> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, FunctionParsingInsights parsing_insights, bool is_arrow_function)
|
||||
: m_name(move(name))
|
||||
, m_source_text(move(source_text))
|
||||
, m_body(move(body))
|
||||
, m_parameters(move(parameters))
|
||||
, m_function_length(function_length)
|
||||
, m_kind(kind)
|
||||
, m_is_strict_mode(is_strict_mode)
|
||||
, m_is_arrow_function(is_arrow_function)
|
||||
, m_parsing_insights(parsing_insights)
|
||||
{
|
||||
if (m_is_arrow_function)
|
||||
VERIFY(!parsing_insights.might_need_arguments_object);
|
||||
}
|
||||
|
||||
FunctionNode::~FunctionNode() = default;
|
||||
|
||||
ThrowCompletionOr<void> FunctionDeclaration::for_each_bound_identifier(ThrowCompletionOrVoidCallback<Identifier const&>&& callback) const
|
||||
{
|
||||
if (!m_name)
|
||||
return {};
|
||||
return callback(*m_name);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> VariableDeclaration::for_each_bound_identifier(ThrowCompletionOrVoidCallback<Identifier const&>&& callback) const
|
||||
{
|
||||
for (auto const& entry : declarations()) {
|
||||
TRY(entry->target().visit(
|
||||
[&](NonnullRefPtr<Identifier const> const& id) {
|
||||
return callback(id);
|
||||
},
|
||||
[&](NonnullRefPtr<BindingPattern const> const& binding) {
|
||||
return binding->for_each_bound_identifier([&](auto const& id) {
|
||||
return callback(id);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> UsingDeclaration::for_each_bound_identifier(ThrowCompletionOrVoidCallback<Identifier const&>&& callback) const
|
||||
{
|
||||
for (auto const& entry : m_declarations) {
|
||||
VERIFY(entry->target().has<NonnullRefPtr<Identifier const>>());
|
||||
TRY(callback(entry->target().get<NonnullRefPtr<Identifier const>>()));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static Utf16String expression_to_string_approximation(Expression const& expression)
|
||||
{
|
||||
if (is<Identifier>(expression))
|
||||
return as<Identifier>(expression).string().to_utf16_string();
|
||||
|
||||
if (is<MemberExpression>(expression)) {
|
||||
auto const& member = as<MemberExpression>(expression);
|
||||
auto object_string = expression_to_string_approximation(member.object());
|
||||
if (member.is_computed()) {
|
||||
auto property_string = expression_to_string_approximation(member.property());
|
||||
return Utf16String::formatted("{}[{}]", object_string, property_string);
|
||||
}
|
||||
if (is<PrivateIdentifier>(member.property()))
|
||||
return Utf16String::formatted("{}.{}", object_string, as<PrivateIdentifier>(member.property()).string());
|
||||
return Utf16String::formatted("{}.{}", object_string, as<Identifier>(member.property()).string());
|
||||
}
|
||||
|
||||
if (is<StringLiteral>(expression))
|
||||
return Utf16String::formatted("'{}'", as<StringLiteral>(expression).value());
|
||||
|
||||
if (is<NumericLiteral>(expression))
|
||||
return Utf16String::formatted("{}", as<NumericLiteral>(expression).value().as_double());
|
||||
|
||||
if (is<ThisExpression>(expression))
|
||||
return "this"_utf16;
|
||||
|
||||
return "<object>"_utf16;
|
||||
}
|
||||
|
||||
Utf16String MemberExpression::to_string_approximation() const
|
||||
{
|
||||
return expression_to_string_approximation(*this);
|
||||
}
|
||||
|
||||
bool MemberExpression::ends_in_private_name() const
|
||||
{
|
||||
if (is_computed())
|
||||
return false;
|
||||
if (is<PrivateIdentifier>(*m_property))
|
||||
return true;
|
||||
if (is<MemberExpression>(*m_property))
|
||||
return static_cast<MemberExpression const&>(*m_property).ends_in_private_name();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScopeNode::has_non_local_lexical_declarations() const
|
||||
{
|
||||
bool result = false;
|
||||
MUST(for_each_lexically_declared_identifier([&](Identifier const& identifier) {
|
||||
if (!identifier.is_local())
|
||||
result = true;
|
||||
}));
|
||||
return result;
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> ScopeNode::for_each_lexically_scoped_declaration(ThrowCompletionOrVoidCallback<Declaration const&>&& callback) const
|
||||
{
|
||||
for (auto& declaration : m_lexical_declarations)
|
||||
TRY(callback(declaration));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> ScopeNode::for_each_lexically_declared_identifier(ThrowCompletionOrVoidCallback<Identifier const&>&& callback) const
|
||||
{
|
||||
for (auto const& declaration : m_lexical_declarations) {
|
||||
TRY(declaration->for_each_bound_identifier([&](auto const& identifier) {
|
||||
return callback(identifier);
|
||||
}));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> ScopeNode::for_each_var_declared_identifier(ThrowCompletionOrVoidCallback<Identifier const&>&& callback) const
|
||||
{
|
||||
for (auto& declaration : m_var_declarations) {
|
||||
TRY(declaration->for_each_bound_identifier([&](auto const& id) {
|
||||
return callback(id);
|
||||
}));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> ScopeNode::for_each_var_function_declaration_in_reverse_order(ThrowCompletionOrVoidCallback<FunctionDeclaration const&>&& callback) const
|
||||
{
|
||||
for (ssize_t i = m_var_declarations.size() - 1; i >= 0; i--) {
|
||||
auto& declaration = m_var_declarations[i];
|
||||
if (is<FunctionDeclaration>(declaration))
|
||||
TRY(callback(static_cast<FunctionDeclaration const&>(*declaration)));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> ScopeNode::for_each_var_scoped_variable_declaration(ThrowCompletionOrVoidCallback<VariableDeclaration const&>&& callback) const
|
||||
{
|
||||
for (auto& declaration : m_var_declarations) {
|
||||
if (!is<FunctionDeclaration>(declaration)) {
|
||||
VERIFY(is<VariableDeclaration>(declaration));
|
||||
TRY(callback(static_cast<VariableDeclaration const&>(*declaration)));
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> ScopeNode::for_each_function_hoistable_with_annexB_extension(ThrowCompletionOrVoidCallback<FunctionDeclaration&>&& callback) const
|
||||
{
|
||||
for (auto& function : m_functions_hoistable_with_annexB_extension) {
|
||||
// We need const_cast here since it might have to set a property on function declaration.
|
||||
TRY(callback(const_cast<FunctionDeclaration&>(*function)));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void ScopeNode::add_lexical_declaration(NonnullRefPtr<Declaration const> declaration)
|
||||
{
|
||||
m_lexical_declarations.append(move(declaration));
|
||||
}
|
||||
|
||||
void ScopeNode::add_var_scoped_declaration(NonnullRefPtr<Declaration const> declaration)
|
||||
{
|
||||
m_var_declarations.append(move(declaration));
|
||||
}
|
||||
|
||||
void ScopeNode::add_hoisted_function(NonnullRefPtr<FunctionDeclaration const> declaration)
|
||||
{
|
||||
m_functions_hoistable_with_annexB_extension.append(move(declaration));
|
||||
}
|
||||
|
||||
void ScopeNode::ensure_function_scope_data() const
|
||||
{
|
||||
if (m_function_scope_data)
|
||||
return;
|
||||
|
||||
auto data = make<FunctionScopeData>();
|
||||
|
||||
// Extract functions_to_initialize from var-scoped function declarations (in reverse order, deduplicated).
|
||||
HashTable<Utf16FlyString> seen_function_names;
|
||||
for (ssize_t i = m_var_declarations.size() - 1; i >= 0; i--) {
|
||||
auto const& declaration = m_var_declarations[i];
|
||||
if (is<FunctionDeclaration>(declaration)) {
|
||||
auto& function_decl = static_cast<FunctionDeclaration const&>(*declaration);
|
||||
if (seen_function_names.set(function_decl.name()) == AK::HashSetResult::InsertedNewEntry)
|
||||
data->functions_to_initialize.append(static_ptr_cast<FunctionDeclaration const>(declaration));
|
||||
}
|
||||
}
|
||||
|
||||
data->has_function_named_arguments = seen_function_names.contains("arguments"_utf16_fly_string);
|
||||
|
||||
// Check if "arguments" is lexically declared.
|
||||
MUST(for_each_lexically_declared_identifier([&](auto const& identifier) {
|
||||
if (identifier.string() == "arguments"_utf16_fly_string)
|
||||
data->has_lexically_declared_arguments = true;
|
||||
}));
|
||||
|
||||
// Extract vars_to_initialize from var declarations.
|
||||
HashTable<Utf16FlyString> seen_var_names;
|
||||
MUST(for_each_var_declared_identifier([&](Identifier const& identifier) {
|
||||
auto const& name = identifier.string();
|
||||
if (seen_var_names.set(name) == AK::HashSetResult::InsertedNewEntry) {
|
||||
data->vars_to_initialize.append({
|
||||
.identifier = identifier,
|
||||
.is_parameter = false,
|
||||
.is_function_name = seen_function_names.contains(name),
|
||||
});
|
||||
|
||||
data->var_names.set(name);
|
||||
|
||||
if (!identifier.is_local()) {
|
||||
data->non_local_var_count++;
|
||||
data->non_local_var_count_for_parameter_expressions++;
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
m_function_scope_data = move(data);
|
||||
}
|
||||
|
||||
Utf16FlyString ExportStatement::local_name_for_default = "*default*"_utf16_fly_string;
|
||||
|
||||
bool ExportStatement::has_export(Utf16FlyString const& export_name) const
|
||||
{
|
||||
return m_entries.contains([&](auto& entry) {
|
||||
// Make sure that empty exported names does not overlap with anything
|
||||
if (entry.kind != ExportEntry::Kind::NamedExport)
|
||||
return false;
|
||||
return entry.export_name == export_name;
|
||||
});
|
||||
}
|
||||
|
||||
bool ImportStatement::has_bound_name(Utf16FlyString const& name) const
|
||||
{
|
||||
return m_entries.contains([&](auto& entry) { return entry.local_name == name; });
|
||||
}
|
||||
|
||||
ModuleRequest::ModuleRequest(Utf16FlyString module_specifier_, Vector<ImportAttribute> attributes)
|
||||
: module_specifier(move(module_specifier_))
|
||||
, attributes(move(attributes))
|
||||
{
|
||||
// 13.3.10.2 EvaluateImportCall ( specifierExpression [ , optionsExpression ] ), https://tc39.es/ecma262/#sec-evaluate-import-call
|
||||
// 16.2.2.4 Static Semantics: WithClauseToAttributes, https://tc39.es/ecma262/#sec-withclausetoattributes
|
||||
// 2. Sort attributes according to the lexicographic order of their [[Key]] field, treating the value of each such
|
||||
// field as a sequence of UTF-16 code unit values.
|
||||
quick_sort(this->attributes, [](ImportAttribute const& lhs, ImportAttribute const& rhs) {
|
||||
return lhs.key < rhs.key;
|
||||
});
|
||||
}
|
||||
|
||||
ByteString SourceRange::filename() const
|
||||
{
|
||||
return code->filename().to_byte_string();
|
||||
}
|
||||
|
||||
NonnullRefPtr<CallExpression> CallExpression::create(SourceRange source_range, NonnullRefPtr<Expression const> callee, ReadonlySpan<Argument> arguments, InvocationStyleEnum invocation_style, InsideParenthesesEnum inside_parens)
|
||||
{
|
||||
return ASTNodeWithTailArray::create<CallExpression>(arguments.size(), move(source_range), move(callee), arguments, invocation_style, inside_parens);
|
||||
}
|
||||
|
||||
NonnullRefPtr<NewExpression> NewExpression::create(SourceRange source_range, NonnullRefPtr<Expression const> callee, ReadonlySpan<Argument> arguments, InvocationStyleEnum invocation_style, InsideParenthesesEnum inside_parens)
|
||||
{
|
||||
return ASTNodeWithTailArray::create<NewExpression>(arguments.size(), move(source_range), move(callee), arguments, invocation_style, inside_parens);
|
||||
}
|
||||
|
||||
NonnullRefPtr<FunctionParameters> FunctionParameters::empty()
|
||||
{
|
||||
static auto empty = adopt_ref(*new FunctionParameters({}));
|
||||
return empty;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Simon Wanner <simon@skyrising.xyz>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Bytecode/Builtins.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
Optional<Builtin> get_builtin(MemberExpression const& expression)
|
||||
{
|
||||
if (expression.is_computed() || !expression.object().is_identifier() || !expression.property().is_identifier())
|
||||
return {};
|
||||
auto base_name = static_cast<Identifier const&>(expression.object()).string();
|
||||
auto property_name = static_cast<Identifier const&>(expression.property()).string();
|
||||
#define CHECK_MEMBER_BUILTIN(name, snake_case_name, base, property, ...) \
|
||||
if (base_name == #base##sv && property_name == #property##sv) \
|
||||
return Builtin::name;
|
||||
JS_ENUMERATE_BUILTINS(CHECK_MEMBER_BUILTIN)
|
||||
#undef CHECK_MEMBER_BUILTIN
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
#include <AK/HashTable.h>
|
||||
#include <AK/TemporaryChange.h>
|
||||
#include <LibGC/RootHashMap.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Bytecode/AsmInterpreter/AsmInterpreter.h>
|
||||
#include <LibJS/Bytecode/BasicBlock.h>
|
||||
#include <LibJS/Bytecode/FormatOperand.h>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
include(libjs_generators)
|
||||
|
||||
set(SOURCES
|
||||
AST.cpp
|
||||
ASTDump.cpp
|
||||
Bytecode/AsmInterpreter/AsmInterpreter.cpp
|
||||
Bytecode/BasicBlock.cpp
|
||||
Bytecode/Builtins.cpp
|
||||
Bytecode/Executable.cpp
|
||||
Bytecode/IdentifierTable.cpp
|
||||
Bytecode/Instruction.cpp
|
||||
|
|
|
|||
97
Libraries/LibJS/ModuleEntry.h
Normal file
97
Libraries/LibJS/ModuleEntry.h
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2026-present, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/Utf16FlyString.h>
|
||||
#include <LibJS/Runtime/ModuleRequest.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
struct ImportEntry {
|
||||
Optional<Utf16FlyString> import_name; // [[ImportName]]: stored string if Optional is not empty, NAMESPACE-OBJECT otherwise
|
||||
Utf16FlyString local_name; // [[LocalName]]
|
||||
Optional<ModuleRequest> m_module_request; // [[ModuleRequest]]
|
||||
|
||||
ImportEntry(Optional<Utf16FlyString> import_name_, Utf16FlyString local_name_)
|
||||
: import_name(move(import_name_))
|
||||
, local_name(move(local_name_))
|
||||
{
|
||||
}
|
||||
|
||||
bool is_namespace() const { return !import_name.has_value(); }
|
||||
|
||||
ModuleRequest const& module_request() const
|
||||
{
|
||||
return m_module_request.value();
|
||||
}
|
||||
};
|
||||
|
||||
// ExportEntry Record, https://tc39.es/ecma262/#table-exportentry-records
|
||||
struct ExportEntry {
|
||||
enum class Kind {
|
||||
NamedExport,
|
||||
ModuleRequestAll,
|
||||
ModuleRequestAllButDefault,
|
||||
// EmptyNamedExport is a special type for export {} from "module",
|
||||
// which should import the module without getting any of the exports
|
||||
// however we don't want give it a fake export name which may get
|
||||
// duplicates
|
||||
EmptyNamedExport,
|
||||
} kind;
|
||||
|
||||
Optional<Utf16FlyString> export_name; // [[ExportName]]
|
||||
Optional<Utf16FlyString> local_or_import_name; // Either [[ImportName]] or [[LocalName]]
|
||||
|
||||
ExportEntry(Kind export_kind, Optional<Utf16FlyString> export_name_, Optional<Utf16FlyString> local_or_import_name_)
|
||||
: kind(export_kind)
|
||||
, export_name(move(export_name_))
|
||||
, local_or_import_name(move(local_or_import_name_))
|
||||
{
|
||||
}
|
||||
|
||||
Optional<ModuleRequest> m_module_request; // [[ModuleRequest]]
|
||||
|
||||
bool is_module_request() const
|
||||
{
|
||||
return m_module_request.has_value();
|
||||
}
|
||||
|
||||
static ExportEntry indirect_export_entry(ModuleRequest module_request, Optional<Utf16FlyString> export_name, Optional<Utf16FlyString> import_name)
|
||||
{
|
||||
ExportEntry entry { Kind::NamedExport, move(export_name), move(import_name) };
|
||||
entry.m_module_request = move(module_request);
|
||||
return entry;
|
||||
}
|
||||
|
||||
ModuleRequest const& module_request() const
|
||||
{
|
||||
return m_module_request.value();
|
||||
}
|
||||
|
||||
static ExportEntry named_export(Utf16FlyString export_name, Utf16FlyString local_name)
|
||||
{
|
||||
return ExportEntry { Kind::NamedExport, move(export_name), move(local_name) };
|
||||
}
|
||||
|
||||
static ExportEntry all_but_default_entry()
|
||||
{
|
||||
return ExportEntry { Kind::ModuleRequestAllButDefault, {}, {} };
|
||||
}
|
||||
|
||||
static ExportEntry all_module_request(Utf16FlyString export_name)
|
||||
{
|
||||
return ExportEntry { Kind::ModuleRequestAll, move(export_name), {} };
|
||||
}
|
||||
|
||||
static ExportEntry empty_named_export()
|
||||
{
|
||||
return ExportEntry { Kind::EmptyNamedExport, {}, {} };
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -952,8 +952,6 @@ ThrowCompletionOr<void> eval_declaration_instantiation(VM& vm, EvalDeclarationDa
|
|||
// iii. Let fobj be ! benv.GetBindingValue(F, false).
|
||||
// iv. Perform ? genv.SetMutableBinding(F, fobj, false).
|
||||
// v. Return unused.
|
||||
if (i < data.annex_b_function_declarations.size())
|
||||
data.annex_b_function_declarations[i]->set_should_do_additional_annexB_steps();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
class FunctionDeclaration;
|
||||
|
||||
GC::Ref<DeclarativeEnvironment> new_declarative_environment(Environment&);
|
||||
JS_API GC::Ref<ObjectEnvironment> new_object_environment(Object&, bool is_with_environment, Environment*);
|
||||
GC::Ref<FunctionEnvironment> new_function_environment(ECMAScriptFunctionObject&, Object* new_target);
|
||||
|
|
@ -106,7 +104,6 @@ struct EvalDeclarationData {
|
|||
Vector<Utf16FlyString> var_scoped_names;
|
||||
|
||||
Vector<Utf16FlyString> annex_b_candidate_names;
|
||||
Vector<NonnullRefPtr<FunctionDeclaration>> annex_b_function_declarations;
|
||||
|
||||
struct LexicalBinding {
|
||||
Utf16FlyString name;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/Utf16FlyString.h>
|
||||
#include <AK/Vector.h>
|
||||
|
|
@ -38,7 +39,17 @@ struct ModuleRequest {
|
|||
{
|
||||
}
|
||||
|
||||
ModuleRequest(Utf16FlyString specifier, Vector<ImportAttribute> attributes);
|
||||
ModuleRequest(Utf16FlyString specifier, Vector<ImportAttribute> attrs)
|
||||
: module_specifier(move(specifier))
|
||||
, attributes(move(attrs))
|
||||
{
|
||||
// 16.2.2.4 Static Semantics: WithClauseToAttributes, https://tc39.es/ecma262/#sec-withclausetoattributes
|
||||
// 2. Sort attributes according to the lexicographic order of their [[Key]] field, treating the value of each such
|
||||
// field as a sequence of UTF-16 code unit values.
|
||||
quick_sort(this->attributes, [](ImportAttribute const& lhs, ImportAttribute const& rhs) {
|
||||
return lhs.key < rhs.key;
|
||||
});
|
||||
}
|
||||
|
||||
void add_attribute(Utf16String key, Utf16String value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#include <AK/Utf16FlyString.h>
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibGC/Root.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/ModuleEntry.h>
|
||||
#include <LibJS/ParserError.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/FunctionKind.h>
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Andreas Kling <andreas@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/Utf16FlyString.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/AST.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
struct ScopeVariable {
|
||||
enum Flag : u16 {
|
||||
None = 0,
|
||||
IsVar = 1 << 0,
|
||||
IsLexical = 1 << 1,
|
||||
IsFunction = 1 << 2,
|
||||
IsCatchParameter = 1 << 3,
|
||||
IsForbiddenLexical = 1 << 4,
|
||||
IsForbiddenVar = 1 << 5,
|
||||
IsBound = 1 << 6,
|
||||
IsParameterCandidate = 1 << 7,
|
||||
IsReferencedInFormalParameters = 1 << 8,
|
||||
};
|
||||
|
||||
u16 flags { 0 };
|
||||
Identifier const* var_identifier { nullptr };
|
||||
RefPtr<FunctionDeclaration const> function_declaration;
|
||||
|
||||
bool has_flag(u16 flag) const { return flags & flag; }
|
||||
};
|
||||
|
||||
struct IdentifierGroup {
|
||||
bool captured_by_nested_function { false };
|
||||
bool used_inside_with_statement { false };
|
||||
Vector<NonnullRefPtr<Identifier>> identifiers;
|
||||
Optional<DeclarationKind> declaration_kind;
|
||||
};
|
||||
|
||||
struct ScopeRecord {
|
||||
enum class ScopeType {
|
||||
Function,
|
||||
Program,
|
||||
Block,
|
||||
ForLoop,
|
||||
With,
|
||||
Catch,
|
||||
ClassStaticInit,
|
||||
ClassField,
|
||||
ClassDeclaration,
|
||||
};
|
||||
|
||||
// NOTE: We really only need ModuleTopLevel and NotModuleTopLevel as the only
|
||||
// difference seems to be in https://tc39.es/ecma262/#sec-static-semantics-varscopeddeclarations
|
||||
// where ModuleItemList only does the VarScopedDeclaration and not the
|
||||
// TopLevelVarScopedDeclarations.
|
||||
enum class ScopeLevel {
|
||||
NotTopLevel,
|
||||
ScriptTopLevel,
|
||||
ModuleTopLevel,
|
||||
FunctionTopLevel,
|
||||
StaticInitTopLevel,
|
||||
};
|
||||
|
||||
ScopeType type;
|
||||
ScopeLevel level;
|
||||
RefPtr<ScopeNode> ast_node;
|
||||
|
||||
HashMap<Utf16FlyString, ScopeVariable> variables;
|
||||
HashMap<Utf16FlyString, IdentifierGroup> identifier_groups;
|
||||
Vector<NonnullRefPtr<FunctionDeclaration const>> functions_to_hoist;
|
||||
|
||||
RefPtr<FunctionParameters const> function_parameters;
|
||||
|
||||
bool contains_access_to_arguments_object_in_non_strict_mode { false };
|
||||
bool contains_direct_call_to_eval { false };
|
||||
bool contains_await_expression { false };
|
||||
bool screwed_by_eval_in_scope_chain { false };
|
||||
bool eval_in_current_function { false };
|
||||
bool uses_this_from_environment { false };
|
||||
bool uses_this { false };
|
||||
bool is_arrow_function { false };
|
||||
bool is_function_declaration { false };
|
||||
bool has_parameter_expressions { false };
|
||||
|
||||
ScopeRecord* parent { nullptr };
|
||||
ScopeRecord* top_level { nullptr };
|
||||
Vector<NonnullOwnPtr<ScopeRecord>> children;
|
||||
|
||||
bool is_top_level() const { return level != ScopeLevel::NotTopLevel; }
|
||||
|
||||
bool has_variable_with_flags(Utf16FlyString const& name, u16 flags) const
|
||||
{
|
||||
auto it = variables.find(name);
|
||||
return it != variables.end() && (it->value.flags & flags);
|
||||
}
|
||||
|
||||
ScopeRecord const* last_function_scope() const
|
||||
{
|
||||
for (auto const* scope = this; scope; scope = scope->parent) {
|
||||
if (scope->type == ScopeType::Function || scope->type == ScopeType::ClassStaticInit)
|
||||
return scope;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ struct JS_API SourceRange {
|
|||
Position start;
|
||||
Position end;
|
||||
|
||||
ByteString filename() const;
|
||||
ByteString filename() const { return code->filename().to_byte_string(); }
|
||||
};
|
||||
|
||||
struct UnrealizedSourceRange {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <LibJS/CyclicModule.h>
|
||||
#include <LibJS/Export.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/ModuleEntry.h>
|
||||
#include <LibJS/Runtime/ExecutionContext.h>
|
||||
|
||||
namespace JS {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
*/
|
||||
|
||||
#include <LibGC/DeferGC.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Module.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/Environment.h>
|
||||
|
|
|
|||
Loading…
Reference in a new issue