From 8ec7e7c07c9bbf142faa0e84fb8d145b6a89bd15 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 19 Mar 2026 13:37:46 -0500 Subject: [PATCH] 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. --- Libraries/LibJS/AST.cpp | 382 --- Libraries/LibJS/AST.h | 2322 ----------------- Libraries/LibJS/ASTDump.cpp | 1058 -------- Libraries/LibJS/Bytecode/Builtins.cpp | 26 - Libraries/LibJS/Bytecode/Interpreter.cpp | 1 - Libraries/LibJS/CMakeLists.txt | 3 - Libraries/LibJS/ModuleEntry.h | 97 + .../LibJS/Runtime/AbstractOperations.cpp | 2 - Libraries/LibJS/Runtime/AbstractOperations.h | 3 - Libraries/LibJS/Runtime/ModuleRequest.h | 13 +- Libraries/LibJS/RustIntegration.h | 2 +- Libraries/LibJS/ScopeRecord.h | 116 - Libraries/LibJS/SourceRange.h | 2 +- Libraries/LibJS/SourceTextModule.h | 1 + Libraries/LibWeb/Bindings/MainThreadVM.cpp | 1 - 15 files changed, 112 insertions(+), 3917 deletions(-) delete mode 100644 Libraries/LibJS/AST.cpp delete mode 100644 Libraries/LibJS/AST.h delete mode 100644 Libraries/LibJS/ASTDump.cpp delete mode 100644 Libraries/LibJS/Bytecode/Builtins.cpp create mode 100644 Libraries/LibJS/ModuleEntry.h delete mode 100644 Libraries/LibJS/ScopeRecord.h diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp deleted file mode 100644 index 07f449c73d..0000000000 --- a/Libraries/LibJS/AST.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2020-2024, Andreas Kling - * Copyright (c) 2020-2023, Linus Groh - * Copyright (c) 2021-2022, David Tuin - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 CallExpression::expression_string() const -{ - if (is(*m_callee)) - return static_cast(*m_callee).string().to_utf16_string(); - - if (is(*m_callee)) - return static_cast(*m_callee).to_string_approximation(); - - return {}; -} - -static Optional nullopt_or_private_identifier_description(Expression const& expression) -{ - if (is(expression)) - return static_cast(expression).string(); - return {}; -} - -Optional ClassField::private_bound_identifier() const -{ - return nullopt_or_private_identifier_description(*m_key); -} - -Optional ClassMethod::private_bound_identifier() const -{ - return nullopt_or_private_identifier_description(*m_key); -} - -ThrowCompletionOr ClassDeclaration::for_each_bound_identifier(ThrowCompletionOrVoidCallback&& 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>()) - return true; - if (entry.initializer) - return true; - if (auto binding_ptr = entry.alias.get_pointer>(); binding_ptr && (*binding_ptr)->contains_expression()) - return true; - } - return false; -} - -ThrowCompletionOr BindingPattern::for_each_bound_identifier(ThrowCompletionOrVoidCallback&& callback) const -{ - for (auto const& entry : entries) { - auto const& alias = entry.alias; - if (alias.has>()) { - TRY(callback(alias.get>())); - } else if (alias.has>()) { - TRY(alias.get>()->for_each_bound_identifier(forward(callback))); - } else { - auto const& name = entry.name; - if (name.has>()) - TRY(callback(name.get>())); - } - } - return {}; -} - -FunctionNode::FunctionNode(RefPtr name, Utf16View source_text, NonnullRefPtr body, NonnullRefPtr 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 FunctionDeclaration::for_each_bound_identifier(ThrowCompletionOrVoidCallback&& callback) const -{ - if (!m_name) - return {}; - return callback(*m_name); -} - -ThrowCompletionOr VariableDeclaration::for_each_bound_identifier(ThrowCompletionOrVoidCallback&& callback) const -{ - for (auto const& entry : declarations()) { - TRY(entry->target().visit( - [&](NonnullRefPtr const& id) { - return callback(id); - }, - [&](NonnullRefPtr const& binding) { - return binding->for_each_bound_identifier([&](auto const& id) { - return callback(id); - }); - })); - } - - return {}; -} - -ThrowCompletionOr UsingDeclaration::for_each_bound_identifier(ThrowCompletionOrVoidCallback&& callback) const -{ - for (auto const& entry : m_declarations) { - VERIFY(entry->target().has>()); - TRY(callback(entry->target().get>())); - } - - return {}; -} - -static Utf16String expression_to_string_approximation(Expression const& expression) -{ - if (is(expression)) - return as(expression).string().to_utf16_string(); - - if (is(expression)) { - auto const& member = as(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(member.property())) - return Utf16String::formatted("{}.{}", object_string, as(member.property()).string()); - return Utf16String::formatted("{}.{}", object_string, as(member.property()).string()); - } - - if (is(expression)) - return Utf16String::formatted("'{}'", as(expression).value()); - - if (is(expression)) - return Utf16String::formatted("{}", as(expression).value().as_double()); - - if (is(expression)) - return "this"_utf16; - - return ""_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(*m_property)) - return true; - if (is(*m_property)) - return static_cast(*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 ScopeNode::for_each_lexically_scoped_declaration(ThrowCompletionOrVoidCallback&& callback) const -{ - for (auto& declaration : m_lexical_declarations) - TRY(callback(declaration)); - - return {}; -} - -ThrowCompletionOr ScopeNode::for_each_lexically_declared_identifier(ThrowCompletionOrVoidCallback&& callback) const -{ - for (auto const& declaration : m_lexical_declarations) { - TRY(declaration->for_each_bound_identifier([&](auto const& identifier) { - return callback(identifier); - })); - } - return {}; -} - -ThrowCompletionOr ScopeNode::for_each_var_declared_identifier(ThrowCompletionOrVoidCallback&& callback) const -{ - for (auto& declaration : m_var_declarations) { - TRY(declaration->for_each_bound_identifier([&](auto const& id) { - return callback(id); - })); - } - return {}; -} - -ThrowCompletionOr ScopeNode::for_each_var_function_declaration_in_reverse_order(ThrowCompletionOrVoidCallback&& callback) const -{ - for (ssize_t i = m_var_declarations.size() - 1; i >= 0; i--) { - auto& declaration = m_var_declarations[i]; - if (is(declaration)) - TRY(callback(static_cast(*declaration))); - } - return {}; -} - -ThrowCompletionOr ScopeNode::for_each_var_scoped_variable_declaration(ThrowCompletionOrVoidCallback&& callback) const -{ - for (auto& declaration : m_var_declarations) { - if (!is(declaration)) { - VERIFY(is(declaration)); - TRY(callback(static_cast(*declaration))); - } - } - return {}; -} - -ThrowCompletionOr ScopeNode::for_each_function_hoistable_with_annexB_extension(ThrowCompletionOrVoidCallback&& 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(*function))); - } - return {}; -} - -void ScopeNode::add_lexical_declaration(NonnullRefPtr declaration) -{ - m_lexical_declarations.append(move(declaration)); -} - -void ScopeNode::add_var_scoped_declaration(NonnullRefPtr declaration) -{ - m_var_declarations.append(move(declaration)); -} - -void ScopeNode::add_hoisted_function(NonnullRefPtr 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(); - - // Extract functions_to_initialize from var-scoped function declarations (in reverse order, deduplicated). - HashTable seen_function_names; - for (ssize_t i = m_var_declarations.size() - 1; i >= 0; i--) { - auto const& declaration = m_var_declarations[i]; - if (is(declaration)) { - auto& function_decl = static_cast(*declaration); - if (seen_function_names.set(function_decl.name()) == AK::HashSetResult::InsertedNewEntry) - data->functions_to_initialize.append(static_ptr_cast(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 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 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::create(SourceRange source_range, NonnullRefPtr callee, ReadonlySpan arguments, InvocationStyleEnum invocation_style, InsideParenthesesEnum inside_parens) -{ - return ASTNodeWithTailArray::create(arguments.size(), move(source_range), move(callee), arguments, invocation_style, inside_parens); -} - -NonnullRefPtr NewExpression::create(SourceRange source_range, NonnullRefPtr callee, ReadonlySpan arguments, InvocationStyleEnum invocation_style, InsideParenthesesEnum inside_parens) -{ - return ASTNodeWithTailArray::create(arguments.size(), move(source_range), move(callee), arguments, invocation_style, inside_parens); -} - -NonnullRefPtr FunctionParameters::empty() -{ - static auto empty = adopt_ref(*new FunctionParameters({})); - return empty; -} - -} diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h deleted file mode 100644 index 09fecdbe63..0000000000 --- a/Libraries/LibJS/AST.h +++ /dev/null @@ -1,2322 +0,0 @@ -/* - * Copyright (c) 2020-2025, Andreas Kling - * Copyright (c) 2020-2022, Linus Groh - * Copyright (c) 2021-2022, David Tuin - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace JS { - -class Declaration; -class ClassDeclaration; -class FunctionDeclaration; -class Identifier; -class MemberExpression; -class VariableDeclaration; -template -static inline NonnullRefPtr -create_ast_node(SourceRange range, Args&&... args) -{ - return adopt_ref(*new T(move(range), forward(args)...)); -} - -struct ASTDumpState { - ByteString prefix; - bool is_last { true }; - bool is_root { true }; - bool use_color { false }; - StringBuilder* output { nullptr }; -}; - -class JS_API ASTNode : public RefCounted { -public: - virtual ~ASTNode() = default; - - // NOTE: This is here to stop ASAN complaining about mismatch between new/delete sizes in ASTNodeWithTailArray. - void operator delete(void* ptr) { ::operator delete(ptr); } - - virtual void dump(ASTDumpState const& state = {}) const; - [[nodiscard]] String dump_to_string() const; - - [[nodiscard]] SourceRange const& source_range() const { return m_source_range; } - u32 start_offset() const { return m_source_range.start.offset; } - u32 end_offset() const { return m_source_range.end.offset; } - - SourceCode const& source_code() const { return *m_source_range.code; } - - void set_end_offset(Badge, u32 end_offset) { m_source_range.end.offset = end_offset; } - - ByteString class_name() const; - - template - bool fast_is() const = delete; - - virtual bool is_new_expression() const { return false; } - virtual bool is_member_expression() const { return false; } - virtual bool is_super_expression() const { return false; } - virtual bool is_function_expression() const { return false; } - virtual bool is_class_expression() const { return false; } - virtual bool is_expression_statement() const { return false; } - virtual bool is_identifier() const { return false; } - virtual bool is_private_identifier() const { return false; } - virtual bool is_scope_node() const { return false; } - virtual bool is_program() const { return false; } - virtual bool is_class_declaration() const { return false; } - virtual bool is_function_declaration() const { return false; } - virtual bool is_variable_declaration() const { return false; } - virtual bool is_import_call() const { return false; } - virtual bool is_array_expression() const { return false; } - virtual bool is_object_expression() const { return false; } - virtual bool is_numeric_literal() const { return false; } - virtual bool is_string_literal() const { return false; } - virtual bool is_boolean_literal() const { return false; } - virtual bool is_null_literal() const { return false; } - virtual bool is_update_expression() const { return false; } - virtual bool is_call_expression() const { return false; } - virtual bool is_labelled_statement() const { return false; } - virtual bool is_iteration_statement() const { return false; } - virtual bool is_class_method() const { return false; } - virtual bool is_spread_expression() const { return false; } - virtual bool is_function_body() const { return false; } - virtual bool is_block_statement() const { return false; } - virtual bool is_primitive_literal() const { return false; } - virtual bool is_optional_chain() const { return false; } - -protected: - explicit ASTNode(SourceRange); - -private: - SourceRange m_source_range; -}; - -// This is a helper class that packs an array of T after the AST node, all in the same allocation. -template -class ASTNodeWithTailArray : public Base { -public: - virtual ~ASTNodeWithTailArray() override - { - for (auto& value : tail_span()) - value.~T(); - } - - ReadonlySpan tail_span() const { return { tail_data(), tail_size() }; } - - T const* tail_data() const { return reinterpret_cast(reinterpret_cast(this) + sizeof(Derived)); } - size_t tail_size() const { return m_tail_size; } - -protected: - template - static NonnullRefPtr create(size_t tail_size, SourceRange source_range, Args&&... args) - { - static_assert(sizeof(ActualDerived) == sizeof(Derived), "This leaf class cannot add more members"); - static_assert(alignof(ActualDerived) % alignof(T) == 0, "Need padding for tail array"); - auto* memory = ::operator new(sizeof(ActualDerived) + tail_size * sizeof(T)); - return adopt_ref(*::new (memory) ActualDerived(move(source_range), forward(args)...)); - } - - ASTNodeWithTailArray(SourceRange source_range, ReadonlySpan values) - : Base(move(source_range)) - , m_tail_size(values.size()) - { - VERIFY(values.size() <= NumericLimits::max()); - for (size_t i = 0; i < values.size(); ++i) - new (&tail_data()[i]) T(values[i]); - } - -private: - T* tail_data() { return reinterpret_cast(reinterpret_cast(this) + sizeof(Derived)); } - - u32 m_tail_size { 0 }; -}; - -enum class DeclarationKind { - None, - Var, - Let, - Const, -}; - -class Statement : public ASTNode { -public: - explicit Statement(SourceRange source_range) - : ASTNode(move(source_range)) - { - } -}; - -// 14.13 Labelled Statements, https://tc39.es/ecma262/#sec-labelled-statements -class LabelledStatement final : public Statement { -public: - LabelledStatement(SourceRange source_range, FlyString label, NonnullRefPtr labelled_item) - : Statement(move(source_range)) - , m_label(move(label)) - , m_labelled_item(move(labelled_item)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - FlyString const& label() const { return m_label; } - FlyString& label() { return m_label; } - NonnullRefPtr const& labelled_item() const { return m_labelled_item; } - -private: - virtual bool is_labelled_statement() const final { return true; } - - FlyString m_label; - NonnullRefPtr m_labelled_item; -}; - -class LabelableStatement : public Statement { -public: - using Statement::Statement; - - Vector const& labels() const { return m_labels; } - virtual void add_label(FlyString string) { m_labels.append(move(string)); } - -protected: - Vector m_labels; -}; - -class IterationStatement : public Statement { -public: - using Statement::Statement; - -private: - virtual bool is_iteration_statement() const final { return true; } -}; - -class EmptyStatement final : public Statement { -public: - explicit EmptyStatement(SourceRange source_range) - : Statement(move(source_range)) - { - } -}; - -class ErrorStatement final : public Statement { -public: - explicit ErrorStatement(SourceRange source_range) - : Statement(move(source_range)) - { - } -}; - -class ExpressionStatement final : public Statement { -public: - ExpressionStatement(SourceRange source_range, NonnullRefPtr expression) - : Statement(move(source_range)) - , m_expression(move(expression)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - Expression const& expression() const { return m_expression; } - -private: - virtual bool is_expression_statement() const override { return true; } - - NonnullRefPtr m_expression; -}; - -template -concept ThrowCompletionOrVoidFunction = requires(Func func, Args... args) { - { - func(args...) - } - -> SameAs>; -}; - -template -class ThrowCompletionOrVoidCallback : public Function(Args...)> { -public: - template - ThrowCompletionOrVoidCallback(CallableType&& callable) - requires(VoidFunction) - : Function(Args...)>([callable = forward(callable)](Args... args) { - callable(args...); - return ThrowCompletionOr {}; - }) - { - } - - template - ThrowCompletionOrVoidCallback(CallableType&& callable) - requires(ThrowCompletionOrVoidFunction) - : Function(Args...)>(forward(callable)) - { - } -}; - -struct VarToInitialize { - Identifier const& identifier; - bool is_parameter { false }; - bool is_function_name { false }; -}; - -struct FunctionScopeData { - Vector> functions_to_initialize; - Vector vars_to_initialize; - HashTable var_names; - bool has_function_named_arguments { false }; - bool has_argument_parameter { false }; - bool has_lexically_declared_arguments { false }; - size_t non_local_var_count { 0 }; - size_t non_local_var_count_for_parameter_expressions { 0 }; -}; - -class JS_API ScopeNode : public Statement { -public: - template - T& append(SourceRange range, Args&&... args) - { - auto child = create_ast_node(range, forward(args)...); - m_children.append(move(child)); - return static_cast(*m_children.last()); - } - void append(NonnullRefPtr child) - { - m_children.append(move(child)); - } - - void shrink_to_fit() - { - m_children.shrink_to_fit(); - m_lexical_declarations.shrink_to_fit(); - m_var_declarations.shrink_to_fit(); - m_functions_hoistable_with_annexB_extension.shrink_to_fit(); - } - - Vector> const& children() const { return m_children; } - virtual void dump(ASTDumpState const& state = {}) const override; - - void add_var_scoped_declaration(NonnullRefPtr variables); - void add_lexical_declaration(NonnullRefPtr variables); - void add_hoisted_function(NonnullRefPtr declaration); - - [[nodiscard]] bool has_lexical_declarations() const { return !m_lexical_declarations.is_empty(); } - [[nodiscard]] bool has_non_local_lexical_declarations() const; - [[nodiscard]] bool has_var_declarations() const { return !m_var_declarations.is_empty(); } - [[nodiscard]] Vector> const& var_declarations() const { return m_var_declarations; } - - [[nodiscard]] size_t var_declaration_count() const { return m_var_declarations.size(); } - [[nodiscard]] size_t lexical_declaration_count() const { return m_lexical_declarations.size(); } - - ThrowCompletionOr for_each_lexically_scoped_declaration(ThrowCompletionOrVoidCallback&& callback) const; - ThrowCompletionOr for_each_lexically_declared_identifier(ThrowCompletionOrVoidCallback&& callback) const; - - ThrowCompletionOr for_each_var_declared_identifier(ThrowCompletionOrVoidCallback&& callback) const; - - ThrowCompletionOr for_each_var_function_declaration_in_reverse_order(ThrowCompletionOrVoidCallback&& callback) const; - ThrowCompletionOr for_each_var_scoped_variable_declaration(ThrowCompletionOrVoidCallback&& callback) const; - - ThrowCompletionOr for_each_function_hoistable_with_annexB_extension(ThrowCompletionOrVoidCallback&& callback) const; - - auto const& local_variables_names() const { return m_local_variables_names; } - size_t add_local_variable(Utf16FlyString name, LocalVariable::DeclarationKind declaration_kind) - { - auto index = m_local_variables_names.size(); - m_local_variables_names.append({ move(name), declaration_kind }); - return index; - } - - FunctionScopeData const* function_scope_data() const { return m_function_scope_data.ptr(); } - void set_function_scope_data(OwnPtr data) { m_function_scope_data = move(data); } - void ensure_function_scope_data() const; - -protected: - explicit ScopeNode(SourceRange source_range) - : Statement(move(source_range)) - { - } - -private: - virtual bool is_scope_node() const final { return true; } - - Vector> m_children; - Vector> m_lexical_declarations; - Vector> m_var_declarations; - - Vector> m_functions_hoistable_with_annexB_extension; - - Vector m_local_variables_names; - mutable OwnPtr m_function_scope_data; -}; - -// ImportEntry Record, https://tc39.es/ecma262/#table-importentry-record-fields -struct ImportEntry { - Optional import_name; // [[ImportName]]: stored string if Optional is not empty, NAMESPACE-OBJECT otherwise - Utf16FlyString local_name; // [[LocalName]] - Optional m_module_request; // [[ModuleRequest]] - - ImportEntry(Optional 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(); - } -}; - -class ImportStatement final : public Statement { -public: - explicit ImportStatement(SourceRange source_range, ModuleRequest from_module, Vector entries = {}) - : Statement(move(source_range)) - , m_module_request(move(from_module)) - , m_entries(move(entries)) - { - for (auto& entry : m_entries) - entry.m_module_request = m_module_request; - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - bool has_bound_name(Utf16FlyString const& name) const; - Vector const& entries() const { return m_entries; } - ModuleRequest const& module_request() const { return m_module_request; } - -private: - ModuleRequest m_module_request; - Vector m_entries; -}; - -// 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 export_name; // [[ExportName]] - Optional local_or_import_name; // Either [[ImportName]] or [[LocalName]] - - ExportEntry(Kind export_kind, Optional export_name_, Optional local_or_import_name_) - : kind(export_kind) - , export_name(move(export_name_)) - , local_or_import_name(move(local_or_import_name_)) - { - } - - Optional m_module_request; // [[ModuleRequest]] - - bool is_module_request() const - { - return m_module_request.has_value(); - } - - static ExportEntry indirect_export_entry(ModuleRequest module_request, Optional export_name, Optional 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, {}, {} }; - } -}; - -class ExportStatement final : public Statement { -public: - static Utf16FlyString local_name_for_default; - - ExportStatement(SourceRange source_range, RefPtr statement, Vector entries, bool is_default_export, Optional module_request) - : Statement(move(source_range)) - , m_statement(move(statement)) - , m_entries(move(entries)) - , m_is_default_export(is_default_export) - , m_module_request(move(module_request)) - { - if (m_module_request.has_value()) { - for (auto& entry : m_entries) - entry.m_module_request = m_module_request.value(); - } - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - bool has_export(Utf16FlyString const& export_name) const; - - bool has_statement() const { return m_statement; } - Vector const& entries() const { return m_entries; } - - bool is_default_export() const { return m_is_default_export; } - - ASTNode const& statement() const - { - VERIFY(m_statement); - return *m_statement; - } - - ModuleRequest const& module_request() const - { - return m_module_request.value(); - } - -private: - RefPtr m_statement; - Vector m_entries; - bool m_is_default_export { false }; - Optional m_module_request; -}; - -class Program final : public ScopeNode { -public: - enum class Type { - Script, - Module - }; - - explicit Program(SourceRange source_range, Type program_type) - : ScopeNode(move(source_range)) - , m_type(program_type) - { - } - - bool is_strict_mode() const { return m_is_strict_mode; } - void set_strict_mode() { m_is_strict_mode = true; } - - Type type() const { return m_type; } - - void append_import(NonnullRefPtr import_statement) - { - m_imports.append(import_statement); - append(move(import_statement)); - } - - void append_export(NonnullRefPtr export_statement) - { - m_exports.append(export_statement); - append(move(export_statement)); - } - - Vector> const& imports() const { return m_imports; } - Vector> const& exports() const { return m_exports; } - - Vector>& imports() { return m_imports; } - Vector>& exports() { return m_exports; } - - bool has_top_level_await() const { return m_has_top_level_await; } - void set_has_top_level_await() { m_has_top_level_await = true; } - -private: - virtual bool is_program() const override { return true; } - - bool m_is_strict_mode { false }; - Type m_type { Type::Script }; - - Vector> m_imports; - Vector> m_exports; - bool m_has_top_level_await { false }; -}; - -class BlockStatement final : public ScopeNode { -public: - explicit BlockStatement(SourceRange source_range) - : ScopeNode(move(source_range)) - { - } - -private: - virtual bool is_block_statement() const override { return true; } -}; - -class FunctionBody final : public ScopeNode { -public: - explicit FunctionBody(SourceRange source_range) - : ScopeNode(move(source_range)) - { - } - - void set_strict_mode() { m_in_strict_mode = true; } - - bool in_strict_mode() const { return m_in_strict_mode; } - -private: - virtual bool is_function_body() const override { return true; } - - bool m_in_strict_mode { false }; -}; - -class Expression : public ASTNode { -public: - explicit Expression(SourceRange source_range) - : ASTNode(move(source_range)) - { - } -}; - -class Declaration : public Statement { -public: - explicit Declaration(SourceRange source_range) - : Statement(move(source_range)) - { - } - - virtual ThrowCompletionOr for_each_bound_identifier(ThrowCompletionOrVoidCallback&& callback) const = 0; - - // 8.1.3 Static Semantics: IsConstantDeclaration, https://tc39.es/ecma262/#sec-static-semantics-isconstantdeclaration - virtual bool is_constant_declaration() const { return false; } - - virtual bool is_lexical_declaration() const { return false; } -}; - -class ErrorDeclaration final : public Declaration { -public: - explicit ErrorDeclaration(SourceRange source_range) - : Declaration(move(source_range)) - { - } - - ThrowCompletionOr for_each_bound_identifier(ThrowCompletionOrVoidCallback&&) const override - { - VERIFY_NOT_REACHED(); - } -}; - -struct BindingPattern : RefCounted { - // This covers both BindingProperty and BindingElement, hence the more generic name - struct BindingEntry { - // If this entry represents a BindingElement, then name will be Empty - Variant, NonnullRefPtr, Empty> name {}; - Variant, NonnullRefPtr, NonnullRefPtr, Empty> alias {}; - RefPtr initializer {}; - bool is_rest { false }; - - bool is_elision() const { return name.has() && alias.has(); } - }; - - enum class Kind { - Array, - Object, - }; - - void dump(ASTDumpState const& state = {}) const; - - ThrowCompletionOr for_each_bound_identifier(ThrowCompletionOrVoidCallback&& callback) const; - - bool contains_expression() const; - - Vector entries; - Kind kind { Kind::Object }; -}; - -class Identifier final : public Expression { -public: - explicit Identifier(SourceRange source_range, Utf16FlyString string) - : Expression(move(source_range)) - , m_string(move(string)) - { - } - - Utf16FlyString const& string() const { return m_string; } - - struct Local { - enum Type : u8 { - None, - Argument, - Variable, - }; - Type type; - u32 index; - - bool is_argument() const { return type == Argument; } - bool is_variable() const { return type == Variable; } - - static Local variable(u32 index) { return { Variable, index }; } - static Local argument(u32 index) { return { Argument, index }; } - }; - - bool is_local() const { return m_local_type != Local::Type::None; } - Local local_index() const - { - VERIFY(m_local_type != Local::Type::None); - return Local { m_local_type, m_local_index }; - } - void set_local_variable_index(u32 index) - { - m_local_type = Local::Type::Variable; - m_local_index = index; - } - void set_argument_index(u32 index) - { - m_local_type = Local::Type::Argument; - m_local_index = index; - } - - bool is_global() const { return m_is_global; } - void set_is_global() { m_is_global = true; } - - [[nodiscard]] DeclarationKind declaration_kind() const { return m_declaration_kind; } - void set_declaration_kind(DeclarationKind kind) { m_declaration_kind = kind; } - - // Returns true if this identifier reference was inside a function scope containing - // a direct call to eval(). Such identifiers cannot be optimized as globals. - bool is_inside_scope_with_eval() const { return m_is_inside_scope_with_eval; } - void set_is_inside_scope_with_eval() { m_is_inside_scope_with_eval = true; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - virtual bool is_identifier() const override { return true; } - - u32 m_local_index; - Utf16FlyString m_string; - - Local::Type m_local_type { Local::Type::None }; - - bool m_is_global { false }; - bool m_is_inside_scope_with_eval { false }; - DeclarationKind m_declaration_kind { DeclarationKind::None }; -}; - -struct FunctionParameter { - Variant, NonnullRefPtr> binding; - RefPtr default_value; - bool is_rest { false }; -}; - -class FunctionParameters : public RefCounted { -public: - static NonnullRefPtr create(Vector parameters) - { - if (parameters.is_empty()) - return empty(); - return adopt_ref(*new FunctionParameters(move(parameters))); - } - - static NonnullRefPtr empty(); - - bool is_empty() const { return m_parameters.is_empty(); } - size_t size() const { return m_parameters.size(); } - Vector const& parameters() const { return m_parameters; } - - Optional get_index_of_parameter_name(Utf16FlyString const& name) const - { - // Iterate backwards to return the last parameter with the same name - for (int i = m_parameters.size() - 1; i >= 0; i--) { - auto& parameter = m_parameters[i]; - if (parameter.binding.has>()) { - auto& identifier = parameter.binding.get>(); - if (identifier->string() == name) - return i; - } - } - return {}; - } - - bool has_rest_parameter_with_name(Utf16FlyString const& name) const - { - for (auto const& parameter : m_parameters) { - if (parameter.is_rest && parameter.binding.has>()) { - if (parameter.binding.get>()->string() == name) - return true; - } - } - return false; - } - -private: - FunctionParameters(Vector parameters) - : m_parameters(move(parameters)) - { - } - - Vector m_parameters; -}; - -// NB: FunctionParsingInsights is defined in FunctionParsingInsights.h -// and re-exported here for convenience. - -class JS_API FunctionNode { -public: - Utf16FlyString name() const { return m_name ? m_name->string() : Utf16FlyString {}; } - RefPtr name_identifier() const { return m_name; } - Utf16View source_text() const { return m_source_text; } - Statement const& body() const { return *m_body; } - auto const& body_ptr() const { return m_body; } - auto const& parameters() const { return m_parameters; } - i32 function_length() const { return m_function_length; } - Vector const& local_variables_names() const { return static_cast(*m_body).local_variables_names(); } - bool is_strict_mode() const { return m_is_strict_mode; } - bool might_need_arguments_object() const { return m_parsing_insights.might_need_arguments_object; } - bool contains_direct_call_to_eval() const { return m_parsing_insights.contains_direct_call_to_eval; } - bool is_arrow_function() const { return m_is_arrow_function; } - FunctionParsingInsights const& parsing_insights() const { return m_parsing_insights; } - FunctionKind kind() const { return m_kind; } - bool uses_this_from_environment() const { return m_parsing_insights.uses_this_from_environment; } - - virtual bool has_name() const = 0; - - virtual ~FunctionNode(); - -protected: - FunctionNode(RefPtr name, Utf16View source_text, NonnullRefPtr body, NonnullRefPtr parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, FunctionParsingInsights parsing_insights, bool is_arrow_function); - void dump(ASTDumpState const& state, ByteString const& class_name, SourceRange const& range) const; - - RefPtr m_name { nullptr }; - -private: - Utf16View m_source_text; - NonnullRefPtr m_body; - NonnullRefPtr m_parameters; - i32 const m_function_length; - FunctionKind m_kind; - bool m_is_strict_mode : 1 { false }; - bool m_is_arrow_function : 1 { false }; - FunctionParsingInsights m_parsing_insights; -}; - -class FunctionDeclaration final - : public Declaration - , public FunctionNode { -public: - static bool must_have_name() { return true; } - - FunctionDeclaration(SourceRange source_range, RefPtr name, Utf16View source_text, NonnullRefPtr body, NonnullRefPtr parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, FunctionParsingInsights insights) - : Declaration(move(source_range)) - , FunctionNode(move(name), source_text, move(body), move(parameters), function_length, kind, is_strict_mode, insights, false) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - ThrowCompletionOr for_each_bound_identifier(ThrowCompletionOrVoidCallback&&) const override; - - virtual bool is_function_declaration() const override { return true; } - - void set_should_do_additional_annexB_steps() { m_is_hoisted = true; } - - bool has_name() const override { return true; } - - virtual ~FunctionDeclaration() { } - -private: - bool m_is_hoisted { false }; -}; - -class FunctionExpression final - : public Expression - , public FunctionNode { -public: - static bool must_have_name() { return false; } - - FunctionExpression(SourceRange source_range, RefPtr name, Utf16View source_text, NonnullRefPtr body, NonnullRefPtr parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, FunctionParsingInsights insights, bool is_arrow_function = false) - : Expression(move(source_range)) - , FunctionNode(move(name), source_text, move(body), move(parameters), function_length, kind, is_strict_mode, insights, is_arrow_function) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - bool has_name() const override { return !name().is_empty(); } - - virtual ~FunctionExpression() { } - -private: - virtual bool is_function_expression() const override { return true; } -}; - -class ErrorExpression final : public Expression { -public: - explicit ErrorExpression(SourceRange source_range) - : Expression(move(source_range)) - { - } -}; - -class YieldExpression final : public Expression { -public: - explicit YieldExpression(SourceRange source_range, RefPtr argument, bool is_yield_from) - : Expression(move(source_range)) - , m_argument(move(argument)) - , m_is_yield_from(is_yield_from) - { - } - - Expression const* argument() const { return m_argument; } - bool is_yield_from() const { return m_is_yield_from; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - RefPtr m_argument; - bool m_is_yield_from { false }; -}; - -class AwaitExpression final : public Expression { -public: - explicit AwaitExpression(SourceRange source_range, NonnullRefPtr argument) - : Expression(move(source_range)) - , m_argument(move(argument)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - NonnullRefPtr m_argument; -}; - -class ReturnStatement final : public Statement { -public: - explicit ReturnStatement(SourceRange source_range, RefPtr argument) - : Statement(move(source_range)) - , m_argument(move(argument)) - { - } - - Expression const* argument() const { return m_argument; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - RefPtr m_argument; -}; - -class IfStatement final : public Statement { -public: - IfStatement(SourceRange source_range, NonnullRefPtr predicate, NonnullRefPtr consequent, RefPtr alternate) - : Statement(move(source_range)) - , m_predicate(move(predicate)) - , m_consequent(move(consequent)) - , m_alternate(move(alternate)) - { - } - - Expression const& predicate() const { return *m_predicate; } - Statement const& consequent() const { return *m_consequent; } - Statement const* alternate() const { return m_alternate; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - NonnullRefPtr m_predicate; - NonnullRefPtr m_consequent; - RefPtr m_alternate; -}; - -class WhileStatement final : public IterationStatement { -public: - WhileStatement(SourceRange source_range, NonnullRefPtr test, NonnullRefPtr body) - : IterationStatement(move(source_range)) - , m_test(move(test)) - , m_body(move(body)) - { - } - - Expression const& test() const { return *m_test; } - Statement const& body() const { return *m_body; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - NonnullRefPtr m_test; - NonnullRefPtr m_body; -}; - -class DoWhileStatement final : public IterationStatement { -public: - DoWhileStatement(SourceRange source_range, NonnullRefPtr test, NonnullRefPtr body) - : IterationStatement(move(source_range)) - , m_test(move(test)) - , m_body(move(body)) - { - } - - Expression const& test() const { return *m_test; } - Statement const& body() const { return *m_body; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - NonnullRefPtr m_test; - NonnullRefPtr m_body; -}; - -class WithStatement final : public Statement { -public: - WithStatement(SourceRange source_range, NonnullRefPtr object, NonnullRefPtr body) - : Statement(move(source_range)) - , m_object(move(object)) - , m_body(move(body)) - { - } - - Expression const& object() const { return *m_object; } - Statement const& body() const { return *m_body; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - NonnullRefPtr m_object; - NonnullRefPtr m_body; -}; - -class ForStatement final : public IterationStatement { -public: - ForStatement(SourceRange source_range, RefPtr init, RefPtr test, RefPtr update, NonnullRefPtr body) - : IterationStatement(move(source_range)) - , m_init(move(init)) - , m_test(move(test)) - , m_update(move(update)) - , m_body(move(body)) - { - } - - ASTNode const* init() const { return m_init; } - Expression const* test() const { return m_test; } - Expression const* update() const { return m_update; } - Statement const& body() const { return *m_body; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - RefPtr m_init; - RefPtr m_test; - RefPtr m_update; - NonnullRefPtr m_body; -}; - -class ForInStatement final : public IterationStatement { -public: - ForInStatement(SourceRange source_range, Variant, NonnullRefPtr> lhs, NonnullRefPtr rhs, NonnullRefPtr body) - : IterationStatement(move(source_range)) - , m_lhs(move(lhs)) - , m_rhs(move(rhs)) - , m_body(move(body)) - { - } - - auto const& lhs() const { return m_lhs; } - Expression const& rhs() const { return *m_rhs; } - Statement const& body() const { return *m_body; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - Variant, NonnullRefPtr> m_lhs; - NonnullRefPtr m_rhs; - NonnullRefPtr m_body; -}; - -class ForOfStatement final : public IterationStatement { -public: - ForOfStatement(SourceRange source_range, Variant, NonnullRefPtr> lhs, NonnullRefPtr rhs, NonnullRefPtr body) - : IterationStatement(move(source_range)) - , m_lhs(move(lhs)) - , m_rhs(move(rhs)) - , m_body(move(body)) - { - } - - auto const& lhs() const { return m_lhs; } - Expression const& rhs() const { return *m_rhs; } - Statement const& body() const { return *m_body; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - Variant, NonnullRefPtr> m_lhs; - NonnullRefPtr m_rhs; - NonnullRefPtr m_body; -}; - -class ForAwaitOfStatement final : public IterationStatement { -public: - ForAwaitOfStatement(SourceRange source_range, Variant, NonnullRefPtr> lhs, NonnullRefPtr rhs, NonnullRefPtr body) - : IterationStatement(move(source_range)) - , m_lhs(move(lhs)) - , m_rhs(move(rhs)) - , m_body(move(body)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - Variant, NonnullRefPtr> m_lhs; - NonnullRefPtr m_rhs; - NonnullRefPtr m_body; -}; - -enum class BinaryOp { - Addition, - Subtraction, - Multiplication, - Division, - Modulo, - Exponentiation, - StrictlyEquals, - StrictlyInequals, - LooselyEquals, - LooselyInequals, - GreaterThan, - GreaterThanEquals, - LessThan, - LessThanEquals, - BitwiseAnd, - BitwiseOr, - BitwiseXor, - LeftShift, - RightShift, - UnsignedRightShift, - In, - InstanceOf, -}; - -class BinaryExpression final : public Expression { -public: - BinaryExpression(SourceRange source_range, BinaryOp op, NonnullRefPtr lhs, NonnullRefPtr rhs) - : Expression(move(source_range)) - , m_op(op) - , m_lhs(move(lhs)) - , m_rhs(move(rhs)) - { - } - - auto const& lhs() const { return m_lhs; } - auto const& rhs() const { return m_rhs; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - BinaryOp m_op; - NonnullRefPtr m_lhs; - NonnullRefPtr m_rhs; -}; - -enum class LogicalOp { - And, - Or, - NullishCoalescing, -}; - -class LogicalExpression final : public Expression { -public: - LogicalExpression(SourceRange source_range, LogicalOp op, NonnullRefPtr lhs, NonnullRefPtr rhs) - : Expression(move(source_range)) - , m_op(op) - , m_lhs(move(lhs)) - , m_rhs(move(rhs)) - { - } - - LogicalOp op() const { return m_op; } - NonnullRefPtr lhs() const { return m_lhs; } - NonnullRefPtr rhs() const { return m_rhs; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - LogicalOp m_op; - NonnullRefPtr m_lhs; - NonnullRefPtr m_rhs; -}; - -enum class UnaryOp { - BitwiseNot, - Not, - Plus, - Minus, - Typeof, - Void, - Delete, -}; - -class UnaryExpression final : public Expression { -public: - UnaryExpression(SourceRange source_range, UnaryOp op, NonnullRefPtr lhs) - : Expression(move(source_range)) - , m_op(op) - , m_lhs(move(lhs)) - { - } - - auto const& lhs() const { return m_lhs; } - auto const& op() const { return m_op; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - UnaryOp m_op; - NonnullRefPtr m_lhs; -}; - -class SequenceExpression final : public Expression { -public: - SequenceExpression(SourceRange source_range, Vector> expressions) - : Expression(move(source_range)) - , m_expressions(move(expressions)) - { - VERIFY(m_expressions.size() >= 2); - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - Vector> m_expressions; -}; - -class PrimitiveLiteral : public Expression { -public: - virtual Value value() const = 0; - -protected: - explicit PrimitiveLiteral(SourceRange source_range) - : Expression(move(source_range)) - { - } - -private: - virtual bool is_primitive_literal() const override { return true; } -}; - -class BooleanLiteral final : public PrimitiveLiteral { -public: - explicit BooleanLiteral(SourceRange source_range, bool value) - : PrimitiveLiteral(move(source_range)) - , m_value(value) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - virtual Value value() const override { return Value(m_value); } - -private: - virtual bool is_boolean_literal() const override { return true; } - - bool m_value { false }; -}; - -class NumericLiteral final : public PrimitiveLiteral { -public: - explicit NumericLiteral(SourceRange source_range, double value) - : PrimitiveLiteral(move(source_range)) - , m_value(value) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - virtual Value value() const override { return m_value; } - -private: - virtual bool is_numeric_literal() const override { return true; } - - Value m_value; -}; - -class BigIntLiteral final : public Expression { -public: - explicit BigIntLiteral(SourceRange source_range, ByteString value) - : Expression(move(source_range)) - , m_value(move(value)) - { - } - - ByteString const& raw_value() const { return m_value; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - ByteString m_value; -}; - -class StringLiteral final : public Expression { -public: - explicit StringLiteral(SourceRange source_range, Utf16String value) - : Expression(move(source_range)) - , m_value(move(value)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - Utf16String const& value() const { return m_value; } - -private: - virtual bool is_string_literal() const override { return true; } - - Utf16String m_value; -}; - -class NullLiteral final : public PrimitiveLiteral { -public: - explicit NullLiteral(SourceRange source_range) - : PrimitiveLiteral(move(source_range)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - virtual Value value() const override { return js_null(); } - -private: - virtual bool is_null_literal() const override { return true; } -}; - -class RegExpLiteral final : public Expression { -public: - RegExpLiteral(SourceRange source_range, regex::Parser::Result parsed_regex, String parsed_pattern, regex::RegexOptions parsed_flags, Utf16String pattern, Utf16String flags) - : Expression(move(source_range)) - , m_parsed_regex(move(parsed_regex)) - , m_parsed_pattern(move(parsed_pattern)) - , m_parsed_flags(parsed_flags) - , m_pattern(move(pattern)) - , m_flags(move(flags)) - { - } - - RegExpLiteral(SourceRange source_range, Utf16String pattern, Utf16String flags, regex::RegexOptions parsed_flags) - : Expression(move(source_range)) - , m_parsed_regex { .bytecode = regex::ByteCode {} } - , m_parsed_flags(parsed_flags) - , m_pattern(move(pattern)) - , m_flags(move(flags)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - regex::Parser::Result const& parsed_regex() const { return m_parsed_regex; } - String const& parsed_pattern() const { return m_parsed_pattern; } - regex::RegexOptions const& parsed_flags() const { return m_parsed_flags; } - Utf16String const& pattern() const { return m_pattern; } - Utf16String const& flags() const { return m_flags; } - - void set_compiled_regex(regex::Parser::Result parsed_regex, String parsed_pattern) const - { - m_parsed_regex = move(parsed_regex); - m_parsed_pattern = move(parsed_pattern); - } - -private: - mutable regex::Parser::Result m_parsed_regex; - mutable String m_parsed_pattern; - regex::RegexOptions m_parsed_flags; - Utf16String m_pattern; - Utf16String m_flags; -}; - -class PrivateIdentifier final : public Expression { -public: - explicit PrivateIdentifier(SourceRange source_range, Utf16FlyString string) - : Expression(move(source_range)) - , m_string(move(string)) - { - } - - Utf16FlyString const& string() const { return m_string; } - - virtual void dump(ASTDumpState const& state = {}) const override; - - virtual bool is_private_identifier() const override { return true; } - -private: - Utf16FlyString m_string; -}; - -class ClassElement : public ASTNode { -public: - ClassElement(SourceRange source_range, bool is_static) - : ASTNode(move(source_range)) - , m_is_static(is_static) - { - } - - enum class ElementKind { - Method, - Field, - StaticInitializer, - }; - - virtual ElementKind class_element_kind() const = 0; - bool is_static() const { return m_is_static; } - - virtual Optional private_bound_identifier() const { return {}; } - -private: - bool m_is_static { false }; -}; - -class ClassMethod final : public ClassElement { -public: - enum class Kind { - Method, - Getter, - Setter, - }; - - ClassMethod(SourceRange source_range, NonnullRefPtr key, NonnullRefPtr function, Kind kind, bool is_static) - : ClassElement(move(source_range), is_static) - , m_key(move(key)) - , m_function(move(function)) - , m_kind(kind) - { - } - - Expression const& key() const { return *m_key; } - FunctionExpression const& function() const { return *m_function; } - Kind kind() const { return m_kind; } - virtual ElementKind class_element_kind() const override { return ElementKind::Method; } - - virtual void dump(ASTDumpState const& state = {}) const override; - virtual Optional private_bound_identifier() const override; - -private: - virtual bool is_class_method() const override { return true; } - NonnullRefPtr m_key; - NonnullRefPtr m_function; - Kind m_kind; -}; - -class ClassField final : public ClassElement { -public: - ClassField(SourceRange source_range, NonnullRefPtr key, RefPtr init, bool is_static) - : ClassElement(move(source_range), is_static) - , m_key(move(key)) - , m_initializer(move(init)) - { - } - - Expression const& key() const { return *m_key; } - RefPtr const& initializer() const { return m_initializer; } - RefPtr& initializer() { return m_initializer; } - - virtual ElementKind class_element_kind() const override { return ElementKind::Field; } - - virtual void dump(ASTDumpState const& state = {}) const override; - virtual Optional private_bound_identifier() const override; - -private: - NonnullRefPtr m_key; - RefPtr m_initializer; -}; - -class StaticInitializer final : public ClassElement { -public: - StaticInitializer(SourceRange source_range, NonnullRefPtr function_body) - : ClassElement(move(source_range), true) - , m_function_body(move(function_body)) - { - } - - virtual ElementKind class_element_kind() const override { return ElementKind::StaticInitializer; } - - FunctionBody const& function_body() const { return *m_function_body; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - NonnullRefPtr m_function_body; -}; - -class SuperExpression final : public Expression { -public: - explicit SuperExpression(SourceRange source_range) - : Expression(move(source_range)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - virtual bool is_super_expression() const override { return true; } -}; - -class ClassExpression final : public Expression { -public: - ClassExpression(SourceRange source_range, RefPtr name, Utf16View source_text, RefPtr constructor, RefPtr super_class, Vector> elements) - : Expression(move(source_range)) - , m_name(move(name)) - , m_source_text(move(source_text)) - , m_constructor(move(constructor)) - , m_super_class(move(super_class)) - , m_elements(move(elements)) - { - } - - Utf16FlyString name() const { return m_name ? m_name->string() : Utf16FlyString {}; } - - Utf16View source_text() const { return m_source_text; } - RefPtr constructor() const { return m_constructor; } - - virtual void dump(ASTDumpState const& state = {}) const override; - - bool has_name() const { return m_name; } - -private: - virtual bool is_class_expression() const override { return true; } - - friend ClassDeclaration; - - RefPtr m_name; - Utf16View m_source_text; - RefPtr m_constructor; - RefPtr m_super_class; - Vector> m_elements; -}; - -class ClassDeclaration final : public Declaration { -public: - ClassDeclaration(SourceRange source_range, NonnullRefPtr class_expression) - : Declaration(move(source_range)) - , m_class_expression(move(class_expression)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - ThrowCompletionOr for_each_bound_identifier(ThrowCompletionOrVoidCallback&&) const override; - - virtual bool is_lexical_declaration() const override { return true; } - - Utf16FlyString name() const { return m_class_expression->name(); } - -private: - virtual bool is_class_declaration() const override { return true; } - - friend ExportStatement; - - NonnullRefPtr m_class_expression; -}; - -// We use this class to mimic Initializer : = AssignmentExpression of -// 10.2.1.3 Runtime Semantics: EvaluateBody, https://tc39.es/ecma262/#sec-runtime-semantics-evaluatebody -class ClassFieldInitializerStatement final : public Statement { -public: - ClassFieldInitializerStatement(SourceRange source_range, NonnullRefPtr expression, Utf16FlyString field_name) - : Statement(move(source_range)) - , m_expression(move(expression)) - , m_class_field_identifier_name(move(field_name)) - { - } - - virtual void dump(ASTDumpState const&) const override; - -private: - NonnullRefPtr m_expression; - Utf16FlyString m_class_field_identifier_name; // [[ClassFieldIdentifierName]] -}; - -class SpreadExpression final : public Expression { -public: - explicit SpreadExpression(SourceRange source_range, NonnullRefPtr target) - : Expression(move(source_range)) - , m_target(move(target)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - virtual bool is_spread_expression() const override { return true; } - - NonnullRefPtr m_target; -}; - -class ThisExpression final : public Expression { -public: - explicit ThisExpression(SourceRange source_range) - : Expression(move(source_range)) - { - } - virtual void dump(ASTDumpState const& state = {}) const override; -}; - -struct CallExpressionArgument { - NonnullRefPtr value; - bool is_spread; -}; - -enum InvocationStyleEnum { - Parenthesized, - NotParenthesized, -}; - -enum InsideParenthesesEnum { - InsideParentheses, - NotInsideParentheses, -}; - -class CallExpression : public ASTNodeWithTailArray { - friend class ASTNodeWithTailArray; - - InvocationStyleEnum m_invocation_style; - InsideParenthesesEnum m_inside_parentheses; - -public: - using Argument = CallExpressionArgument; - - static NonnullRefPtr create(SourceRange, NonnullRefPtr callee, ReadonlySpan arguments, InvocationStyleEnum invocation_style, InsideParenthesesEnum inside_parens); - - virtual void dump(ASTDumpState const& state = {}) const override; - - Expression const& callee() const { return m_callee; } - - ReadonlySpan arguments() const { return tail_span(); } - - bool is_parenthesized() const { return m_invocation_style == InvocationStyleEnum::Parenthesized; } - bool is_inside_parens() const { return m_inside_parentheses == InsideParenthesesEnum::InsideParentheses; } - void set_inside_parens() { m_inside_parentheses = InsideParenthesesEnum::InsideParentheses; } - -protected: - CallExpression(SourceRange source_range, NonnullRefPtr callee, ReadonlySpan arguments, InvocationStyleEnum invocation_style, InsideParenthesesEnum inside_parens = InsideParenthesesEnum::NotInsideParentheses) - : ASTNodeWithTailArray(move(source_range), arguments) - , m_invocation_style(invocation_style) - , m_inside_parentheses(inside_parens) - , m_callee(move(callee)) - { - } - - virtual bool is_call_expression() const override { return true; } - - Optional expression_string() const; - - NonnullRefPtr m_callee; -}; - -class NewExpression final : public CallExpression { - friend class ASTNodeWithTailArray; - -public: - static NonnullRefPtr create(SourceRange, NonnullRefPtr callee, ReadonlySpan arguments, InvocationStyleEnum invocation_style, InsideParenthesesEnum inside_parens); - - virtual bool is_new_expression() const override { return true; } - -private: - NewExpression(SourceRange source_range, NonnullRefPtr callee, ReadonlySpan arguments, InvocationStyleEnum invocation_style, InsideParenthesesEnum inside_parens) - : CallExpression(move(source_range), move(callee), arguments, invocation_style, inside_parens) - { - } -}; - -static_assert(sizeof(NewExpression) == sizeof(CallExpression), "Adding members to NewExpression will break CallExpression memory layout"); - -class SuperCall final : public Expression { -public: - // This is here to be able to make a constructor like - // constructor(...args) { super(...args); } which does not use @@iterator of %Array.prototype%. - enum class IsPartOfSyntheticConstructor { - No, - Yes, - }; - - SuperCall(SourceRange source_range, Vector arguments) - : Expression(move(source_range)) - , m_arguments(move(arguments)) - , m_is_synthetic(IsPartOfSyntheticConstructor::No) - { - } - - SuperCall(SourceRange source_range, IsPartOfSyntheticConstructor is_part_of_synthetic_constructor, CallExpression::Argument constructor_argument) - : Expression(move(source_range)) - , m_arguments({ move(constructor_argument) }) - , m_is_synthetic(IsPartOfSyntheticConstructor::Yes) - { - VERIFY(is_part_of_synthetic_constructor == IsPartOfSyntheticConstructor::Yes); - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - Vector const m_arguments; - IsPartOfSyntheticConstructor const m_is_synthetic; -}; - -enum class AssignmentOp { - Assignment, - AdditionAssignment, - SubtractionAssignment, - MultiplicationAssignment, - DivisionAssignment, - ModuloAssignment, - ExponentiationAssignment, - BitwiseAndAssignment, - BitwiseOrAssignment, - BitwiseXorAssignment, - LeftShiftAssignment, - RightShiftAssignment, - UnsignedRightShiftAssignment, - AndAssignment, - OrAssignment, - NullishAssignment, -}; - -class AssignmentExpression final : public Expression { -public: - AssignmentExpression(SourceRange source_range, AssignmentOp op, NonnullRefPtr lhs, NonnullRefPtr rhs) - : Expression(move(source_range)) - , m_op(op) - , m_lhs(move(lhs)) - , m_rhs(move(rhs)) - { - } - - AssignmentExpression(SourceRange source_range, AssignmentOp op, NonnullRefPtr lhs, NonnullRefPtr rhs) - : Expression(move(source_range)) - , m_op(op) - , m_lhs(move(lhs)) - , m_rhs(move(rhs)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - AssignmentOp m_op; - Variant, NonnullRefPtr> m_lhs; - NonnullRefPtr m_rhs; -}; - -enum class UpdateOp { - Increment, - Decrement, -}; - -class UpdateExpression final : public Expression { -public: - UpdateExpression(SourceRange source_range, UpdateOp op, NonnullRefPtr argument, bool prefixed = false) - : Expression(move(source_range)) - , m_op(op) - , m_argument(move(argument)) - , m_prefixed(prefixed) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - virtual bool is_update_expression() const override { return true; } - - UpdateOp m_op; - NonnullRefPtr m_argument; - bool m_prefixed; -}; - -class VariableDeclarator final : public ASTNode { -public: - VariableDeclarator(SourceRange source_range, NonnullRefPtr id) - : ASTNode(move(source_range)) - , m_target(move(id)) - { - } - - VariableDeclarator(SourceRange source_range, NonnullRefPtr target, RefPtr init) - : ASTNode(move(source_range)) - , m_target(move(target)) - , m_init(move(init)) - { - } - - VariableDeclarator(SourceRange source_range, Variant, NonnullRefPtr> target, RefPtr init) - : ASTNode(move(source_range)) - , m_target(move(target)) - , m_init(move(init)) - { - } - - auto& target() const { return m_target; } - Expression const* init() const { return m_init; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - Variant, NonnullRefPtr> m_target; - RefPtr m_init; -}; - -class VariableDeclaration final : public Declaration { -public: - VariableDeclaration(SourceRange source_range, DeclarationKind declaration_kind, Vector> declarations) - : Declaration(move(source_range)) - , m_declaration_kind(declaration_kind) - , m_declarations(move(declarations)) - { - } - - DeclarationKind declaration_kind() const { return m_declaration_kind; } - - virtual void dump(ASTDumpState const& state = {}) const override; - - Vector> const& declarations() const { return m_declarations; } - - ThrowCompletionOr for_each_bound_identifier(ThrowCompletionOrVoidCallback&&) const override; - - virtual bool is_constant_declaration() const override { return m_declaration_kind == DeclarationKind::Const; } - - virtual bool is_lexical_declaration() const override { return m_declaration_kind != DeclarationKind::Var; } - -private: - virtual bool is_variable_declaration() const override { return true; } - - DeclarationKind m_declaration_kind; - Vector> m_declarations; -}; - -class UsingDeclaration final : public Declaration { -public: - UsingDeclaration(SourceRange source_range, Vector> declarations) - : Declaration(move(source_range)) - , m_declarations(move(declarations)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - ThrowCompletionOr for_each_bound_identifier(ThrowCompletionOrVoidCallback&&) const override; - - virtual bool is_constant_declaration() const override { return true; } - - virtual bool is_lexical_declaration() const override { return true; } - - Vector> const& declarations() const { return m_declarations; } - -private: - Vector> m_declarations; -}; - -class ObjectProperty final : public ASTNode { -public: - enum class Type : u8 { - KeyValue, - Getter, - Setter, - Spread, - ProtoSetter, - }; - - ObjectProperty(SourceRange source_range, NonnullRefPtr key, RefPtr value, Type property_type, bool is_method) - : ASTNode(move(source_range)) - , m_property_type(property_type) - , m_is_method(is_method) - , m_key(move(key)) - , m_value(move(value)) - { - } - - Expression const& key() const { return m_key; } - Expression const& value() const - { - VERIFY(m_value); - return *m_value; - } - - Type type() const { return m_property_type; } - bool is_method() const { return m_is_method; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - Type m_property_type; - bool m_is_method { false }; - NonnullRefPtr m_key; - RefPtr m_value; -}; - -class ObjectExpression final : public Expression { -public: - explicit ObjectExpression(SourceRange source_range, Vector> properties = {}) - : Expression(move(source_range)) - , m_properties(move(properties)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - virtual bool is_object_expression() const override { return true; } - - Vector> m_properties; -}; - -class ArrayExpression final : public Expression { -public: - ArrayExpression(SourceRange source_range, Vector> elements) - : Expression(move(source_range)) - , m_elements(move(elements)) - { - } - - Vector> const& elements() const { return m_elements; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - virtual bool is_array_expression() const override { return true; } - - Vector> m_elements; -}; - -class TemplateLiteral final : public Expression { -public: - TemplateLiteral(SourceRange source_range, Vector> expressions) - : Expression(move(source_range)) - , m_expressions(move(expressions)) - { - } - - TemplateLiteral(SourceRange source_range, Vector> expressions, Vector> raw_strings) - : Expression(move(source_range)) - , m_expressions(move(expressions)) - , m_raw_strings(move(raw_strings)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - Vector> const& expressions() const { return m_expressions; } - Vector> const& raw_strings() const { return m_raw_strings; } - -private: - Vector> const m_expressions; - Vector> const m_raw_strings; -}; - -class TaggedTemplateLiteral final : public Expression { -public: - TaggedTemplateLiteral(SourceRange source_range, NonnullRefPtr tag, NonnullRefPtr template_literal) - : Expression(move(source_range)) - , m_tag(move(tag)) - , m_template_literal(move(template_literal)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - NonnullRefPtr const m_tag; - NonnullRefPtr const m_template_literal; -}; - -class MemberExpression final : public Expression { -public: - MemberExpression(SourceRange source_range, NonnullRefPtr object, NonnullRefPtr property, bool computed = false) - : Expression(move(source_range)) - , m_computed(computed) - , m_object(move(object)) - , m_property(move(property)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - bool is_computed() const { return m_computed; } - Expression const& object() const { return *m_object; } - Expression const& property() const { return *m_property; } - - Utf16String to_string_approximation() const; - - bool ends_in_private_name() const; - -private: - virtual bool is_member_expression() const override { return true; } - - bool m_computed { false }; - NonnullRefPtr m_object; - NonnullRefPtr m_property; -}; - -class OptionalChain final : public Expression { -public: - enum class Mode { - Optional, - NotOptional, - }; - - struct Call { - Vector arguments; - Mode mode; - }; - struct ComputedReference { - NonnullRefPtr expression; - Mode mode; - }; - struct MemberReference { - NonnullRefPtr identifier; - Mode mode; - }; - struct PrivateMemberReference { - NonnullRefPtr private_identifier; - Mode mode; - }; - - using Reference = Variant; - - OptionalChain(SourceRange source_range, NonnullRefPtr base, Vector references) - : Expression(move(source_range)) - , m_base(move(base)) - , m_references(move(references)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - Expression const& base() const { return *m_base; } - Vector const& references() const { return m_references; } - -private: - virtual bool is_optional_chain() const override { return true; } - - NonnullRefPtr m_base; - Vector m_references; -}; - -class MetaProperty final : public Expression { -public: - enum class Type { - NewTarget, - ImportMeta, - }; - - MetaProperty(SourceRange source_range, Type type) - : Expression(move(source_range)) - , m_type(type) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - Type m_type; -}; - -class ImportCall final : public Expression { -public: - ImportCall(SourceRange source_range, NonnullRefPtr specifier, RefPtr options) - : Expression(move(source_range)) - , m_specifier(move(specifier)) - , m_options(move(options)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - virtual bool is_import_call() const override { return true; } - - NonnullRefPtr m_specifier; - RefPtr m_options; -}; - -class ConditionalExpression final : public Expression { -public: - ConditionalExpression(SourceRange source_range, NonnullRefPtr test, NonnullRefPtr consequent, NonnullRefPtr alternate) - : Expression(move(source_range)) - , m_test(move(test)) - , m_consequent(move(consequent)) - , m_alternate(move(alternate)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - NonnullRefPtr m_test; - NonnullRefPtr m_consequent; - NonnullRefPtr m_alternate; -}; - -class CatchClause final : public ASTNode { -public: - CatchClause(SourceRange source_range, NonnullRefPtr parameter, NonnullRefPtr body) - : ASTNode(move(source_range)) - , m_parameter(move(parameter)) - , m_body(move(body)) - { - } - - CatchClause(SourceRange source_range, NonnullRefPtr parameter, NonnullRefPtr body) - : ASTNode(move(source_range)) - , m_parameter(move(parameter)) - , m_body(move(body)) - { - } - - CatchClause(SourceRange source_range, NonnullRefPtr body) - : ASTNode(move(source_range)) - , m_parameter(Empty {}) - , m_body(move(body)) - { - } - - auto& parameter() const { return m_parameter; } - BlockStatement const& body() const { return m_body; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - Variant, NonnullRefPtr, Empty> m_parameter; - NonnullRefPtr m_body; -}; - -class TryStatement final : public Statement { -public: - TryStatement(SourceRange source_range, NonnullRefPtr block, RefPtr handler, RefPtr finalizer) - : Statement(move(source_range)) - , m_block(move(block)) - , m_handler(move(handler)) - , m_finalizer(move(finalizer)) - { - } - - BlockStatement const& block() const { return m_block; } - CatchClause const* handler() const { return m_handler; } - BlockStatement const* finalizer() const { return m_finalizer; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - NonnullRefPtr m_block; - RefPtr m_handler; - RefPtr m_finalizer; -}; - -class ThrowStatement final : public Statement { -public: - explicit ThrowStatement(SourceRange source_range, NonnullRefPtr argument) - : Statement(move(source_range)) - , m_argument(move(argument)) - { - } - - Expression const& argument() const { return m_argument; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - NonnullRefPtr m_argument; -}; - -class SwitchCase final : public ScopeNode { -public: - SwitchCase(SourceRange source_range, RefPtr test) - : ScopeNode(move(source_range)) - , m_test(move(test)) - { - } - - Expression const* test() const { return m_test; } - - virtual void dump(ASTDumpState const& state = {}) const override; - -private: - RefPtr m_test; -}; - -class SwitchStatement final : public ScopeNode { -public: - SwitchStatement(SourceRange source_range, NonnullRefPtr discriminant) - : ScopeNode(move(source_range)) - , m_discriminant(move(discriminant)) - { - } - - virtual void dump(ASTDumpState const& state = {}) const override; - - void add_case(NonnullRefPtr switch_case) { m_cases.append(move(switch_case)); } - -private: - NonnullRefPtr m_discriminant; - Vector> m_cases; -}; - -class BreakStatement final : public Statement { -public: - BreakStatement(SourceRange source_range, Optional target_label) - : Statement(move(source_range)) - , m_target_label(move(target_label)) - { - } - - Optional const& target_label() const { return m_target_label; } - -private: - Optional m_target_label; -}; - -class ContinueStatement final : public Statement { -public: - ContinueStatement(SourceRange source_range, Optional target_label) - : Statement(move(source_range)) - , m_target_label(move(target_label)) - { - } - - Optional const& target_label() const { return m_target_label; } - -private: - Optional m_target_label; -}; - -class DebuggerStatement final : public Statement { -public: - explicit DebuggerStatement(SourceRange source_range) - : Statement(move(source_range)) - { - } -}; - -class SyntheticReferenceExpression final : public Expression { -public: - explicit SyntheticReferenceExpression(SourceRange source_range, Reference reference, Value value) - : Expression(move(source_range)) - , m_reference(move(reference)) - , m_value(value) - { - } - -private: - Reference m_reference; - Value m_value; -}; - -template<> -inline bool ASTNode::fast_is() const { return is_new_expression(); } - -template<> -inline bool ASTNode::fast_is() const { return is_member_expression(); } - -template<> -inline bool ASTNode::fast_is() const { return is_super_expression(); } - -template<> -inline bool ASTNode::fast_is() const { return is_function_expression(); } - -template<> -inline bool ASTNode::fast_is() const { return is_class_expression(); } - -template<> -inline bool ASTNode::fast_is() const { return is_identifier(); } - -template<> -inline bool ASTNode::fast_is() const { return is_private_identifier(); } - -template<> -inline bool ASTNode::fast_is() const { return is_expression_statement(); } - -template<> -inline bool ASTNode::fast_is() const { return is_scope_node(); } - -template<> -inline bool ASTNode::fast_is() const { return is_program(); } - -template<> -inline bool ASTNode::fast_is() const { return is_class_declaration(); } - -template<> -inline bool ASTNode::fast_is() const { return is_function_declaration(); } - -template<> -inline bool ASTNode::fast_is() const { return is_variable_declaration(); } - -template<> -inline bool ASTNode::fast_is() const { return is_array_expression(); } - -template<> -inline bool ASTNode::fast_is() const { return is_object_expression(); } - -template<> -inline bool ASTNode::fast_is() const { return is_import_call(); } - -template<> -inline bool ASTNode::fast_is() const { return is_numeric_literal(); } - -template<> -inline bool ASTNode::fast_is() const { return is_boolean_literal(); } - -template<> -inline bool ASTNode::fast_is() const { return is_null_literal(); } - -template<> -inline bool ASTNode::fast_is() const { return is_string_literal(); } - -template<> -inline bool ASTNode::fast_is() const { return is_update_expression(); } - -template<> -inline bool ASTNode::fast_is() const { return is_call_expression(); } - -template<> -inline bool ASTNode::fast_is() const { return is_labelled_statement(); } - -template<> -inline bool ASTNode::fast_is() const { return is_iteration_statement(); } - -template<> -inline bool ASTNode::fast_is() const { return is_class_method(); } - -template<> -inline bool ASTNode::fast_is() const { return is_spread_expression(); } - -template<> -inline bool ASTNode::fast_is() const { return is_function_body(); } - -template<> -inline bool ASTNode::fast_is() const { return is_block_statement(); } - -template<> -inline bool ASTNode::fast_is() const { return is_primitive_literal(); } - -template<> -inline bool ASTNode::fast_is() const { return is_optional_chain(); } - -} diff --git a/Libraries/LibJS/ASTDump.cpp b/Libraries/LibJS/ASTDump.cpp deleted file mode 100644 index 5521af369f..0000000000 --- a/Libraries/LibJS/ASTDump.cpp +++ /dev/null @@ -1,1058 +0,0 @@ -/* - * Copyright (c) 2020-2024, Andreas Kling - * Copyright (c) 2020-2023, Linus Groh - * Copyright (c) 2021-2022, David Tuin - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace JS { - -// ANSI color codes for AST dump colorization. -static constexpr auto s_reset = "\033[0m"sv; -static constexpr auto s_dim = "\033[2m"sv; -static constexpr auto s_green = "\033[32m"sv; -static constexpr auto s_yellow = "\033[33m"sv; -static constexpr auto s_cyan = "\033[36m"sv; -static constexpr auto s_magenta = "\033[35m"sv; -static constexpr auto s_white_bold = "\033[1;37m"sv; - -static void print_node(ASTDumpState const& state, StringView text) -{ - if (state.output) { - if (state.is_root) { - state.output->appendff("{}\n", text); - } else if (state.use_color) { - state.output->appendff("{}{}{}{}{}\n", state.prefix, - s_dim, state.is_last ? "\xe2\x94\x94\xe2\x94\x80 "sv : "\xe2\x94\x9c\xe2\x94\x80 "sv, - s_reset, text); - } else { - state.output->appendff("{}{}{}\n", state.prefix, state.is_last ? "\xe2\x94\x94\xe2\x94\x80 "sv : "\xe2\x94\x9c\xe2\x94\x80 "sv, text); - } - } else { - if (state.is_root) { - outln("{}", text); - } else if (state.use_color) { - outln("{}{}{}{}{}", state.prefix, - s_dim, state.is_last ? "\xe2\x94\x94\xe2\x94\x80 "sv : "\xe2\x94\x9c\xe2\x94\x80 "sv, - s_reset, text); - } else { - outln("{}{}{}", state.prefix, state.is_last ? "\xe2\x94\x94\xe2\x94\x80 "sv : "\xe2\x94\x9c\xe2\x94\x80 "sv, text); - } - } -} - -static ByteString child_prefix(ASTDumpState const& state) -{ - if (state.is_root) - return {}; - if (state.use_color) - return ByteString::formatted("{}{}{}{}", state.prefix, s_dim, state.is_last ? " "sv : "\xe2\x94\x82 "sv, s_reset); - return ByteString::formatted("{}{}", state.prefix, state.is_last ? " "sv : "\xe2\x94\x82 "sv); -} - -static ASTDumpState child_state(ASTDumpState const& state, bool is_last) -{ - return { child_prefix(state), is_last, false, state.use_color, state.output }; -} - -static ByteString format_position(ASTDumpState const& state, SourceRange const& range) -{ - if (range.start.line == 0) - return {}; - if (state.use_color) - return ByteString::formatted(" {}@{}:{}{}", s_dim, range.start.line, range.start.column, s_reset); - return ByteString::formatted(" @{}:{}", range.start.line, range.start.column); -} - -static ByteString color_node_name(ASTDumpState const& state, StringView name) -{ - if (!state.use_color) - return ByteString(name); - return ByteString::formatted("{}{}{}", s_white_bold, name, s_reset); -} - -template -static ByteString color_string(ASTDumpState const& state, T const& value) -{ - if (!state.use_color) - return ByteString::formatted("\"{}\"", value); - return ByteString::formatted("{}\"{}\"{}", s_green, value, s_reset); -} - -static ByteString color_number(ASTDumpState const& state, auto value) -{ - if (!state.use_color) - return ByteString::formatted("{}", value); - return ByteString::formatted("{}{}{}", s_magenta, value, s_reset); -} - -static ByteString color_op(ASTDumpState const& state, char const* op) -{ - if (!state.use_color) - return ByteString::formatted("({})", op); - return ByteString::formatted("({}{}{})", s_yellow, op, s_reset); -} - -static ByteString color_label(ASTDumpState const& state, StringView label) -{ - if (!state.use_color) - return ByteString(label); - return ByteString::formatted("{}{}{}", s_dim, label, s_reset); -} - -static ByteString color_local(ASTDumpState const& state, Identifier::Local const& local) -{ - auto kind = local.is_argument() ? "argument"sv : "variable"sv; - if (!state.use_color) - return ByteString::formatted("[{}:{}]", kind, local.index); - return ByteString::formatted("{}[{}:{}]{}", s_cyan, kind, local.index, s_reset); -} - -static ByteString color_global(ASTDumpState const& state) -{ - if (!state.use_color) - return "[global]"_string.to_byte_string(); - return ByteString::formatted("{}[global]{}", s_yellow, s_reset); -} - -static ByteString color_flag(ASTDumpState const& state, StringView flag) -{ - if (!state.use_color) - return ByteString::formatted("[{}]", flag); - return ByteString::formatted("{}[{}]{}", s_dim, flag, s_reset); -} - -static char const* binary_op_to_string(BinaryOp op) -{ - switch (op) { - case BinaryOp::Addition: - return "+"; - case BinaryOp::Subtraction: - return "-"; - case BinaryOp::Multiplication: - return "*"; - case BinaryOp::Division: - return "/"; - case BinaryOp::Modulo: - return "%"; - case BinaryOp::Exponentiation: - return "**"; - case BinaryOp::StrictlyEquals: - return "==="; - case BinaryOp::StrictlyInequals: - return "!=="; - case BinaryOp::LooselyEquals: - return "=="; - case BinaryOp::LooselyInequals: - return "!="; - case BinaryOp::GreaterThan: - return ">"; - case BinaryOp::GreaterThanEquals: - return ">="; - case BinaryOp::LessThan: - return "<"; - case BinaryOp::LessThanEquals: - return "<="; - case BinaryOp::BitwiseAnd: - return "&"; - case BinaryOp::BitwiseOr: - return "|"; - case BinaryOp::BitwiseXor: - return "^"; - case BinaryOp::LeftShift: - return "<<"; - case BinaryOp::RightShift: - return ">>"; - case BinaryOp::UnsignedRightShift: - return ">>>"; - case BinaryOp::In: - return "in"; - case BinaryOp::InstanceOf: - return "instanceof"; - } - VERIFY_NOT_REACHED(); -} - -static char const* logical_op_to_string(LogicalOp op) -{ - switch (op) { - case LogicalOp::And: - return "&&"; - case LogicalOp::Or: - return "||"; - case LogicalOp::NullishCoalescing: - return "??"; - } - VERIFY_NOT_REACHED(); -} - -static char const* unary_op_to_string(UnaryOp op) -{ - switch (op) { - case UnaryOp::BitwiseNot: - return "~"; - case UnaryOp::Not: - return "!"; - case UnaryOp::Plus: - return "+"; - case UnaryOp::Minus: - return "-"; - case UnaryOp::Typeof: - return "typeof"; - case UnaryOp::Void: - return "void"; - case UnaryOp::Delete: - return "delete"; - } - VERIFY_NOT_REACHED(); -} - -static char const* assignment_op_to_string(AssignmentOp op) -{ - switch (op) { - case AssignmentOp::Assignment: - return "="; - case AssignmentOp::AdditionAssignment: - return "+="; - case AssignmentOp::SubtractionAssignment: - return "-="; - case AssignmentOp::MultiplicationAssignment: - return "*="; - case AssignmentOp::DivisionAssignment: - return "/="; - case AssignmentOp::ModuloAssignment: - return "%="; - case AssignmentOp::ExponentiationAssignment: - return "**="; - case AssignmentOp::BitwiseAndAssignment: - return "&="; - case AssignmentOp::BitwiseOrAssignment: - return "|="; - case AssignmentOp::BitwiseXorAssignment: - return "^="; - case AssignmentOp::LeftShiftAssignment: - return "<<="; - case AssignmentOp::RightShiftAssignment: - return ">>="; - case AssignmentOp::UnsignedRightShiftAssignment: - return ">>>="; - case AssignmentOp::AndAssignment: - return "&&="; - case AssignmentOp::OrAssignment: - return "||="; - case AssignmentOp::NullishAssignment: - return "\?\?="; - } - VERIFY_NOT_REACHED(); -} - -static char const* update_op_to_string(UpdateOp op) -{ - switch (op) { - case UpdateOp::Increment: - return "++"; - case UpdateOp::Decrement: - return "--"; - } - VERIFY_NOT_REACHED(); -} - -static char const* declaration_kind_to_string(DeclarationKind kind) -{ - switch (kind) { - case DeclarationKind::None: - VERIFY_NOT_REACHED(); - case DeclarationKind::Let: - return "let"; - case DeclarationKind::Var: - return "var"; - case DeclarationKind::Const: - return "const"; - } - VERIFY_NOT_REACHED(); -} - -static char const* class_method_kind_to_string(ClassMethod::Kind kind) -{ - switch (kind) { - case ClassMethod::Kind::Method: - return "method"; - case ClassMethod::Kind::Getter: - return "getter"; - case ClassMethod::Kind::Setter: - return "setter"; - } - VERIFY_NOT_REACHED(); -} - -static ByteString format_assert_clauses(ModuleRequest const& request) -{ - if (request.attributes.is_empty()) - return {}; - StringBuilder builder; - builder.append(" ["sv); - for (size_t i = 0; i < request.attributes.size(); ++i) { - if (i > 0) - builder.append(", "sv); - builder.appendff("{}: {}", request.attributes[i].key, request.attributes[i].value); - } - builder.append(']'); - return builder.to_byte_string(); -} - -void ASTNode::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, class_name()), format_position(state, source_range()))); -} - -void ScopeNode::dump(ASTDumpState const& state) const -{ - StringBuilder description; - description.append(color_node_name(state, class_name())); - if (is(*this)) { - auto const& program = static_cast(*this); - description.appendff(" {}", color_op(state, program.type() == Program::Type::Module ? "module" : "script")); - if (program.is_strict_mode()) - description.appendff(" {}", color_flag(state, "strict"sv)); - if (program.has_top_level_await()) - description.appendff(" {}", color_flag(state, "top-level-await"sv)); - } - description.append(format_position(state, source_range())); - print_node(state, description.to_byte_string()); - for (size_t i = 0; i < m_children.size(); ++i) - m_children[i]->dump(child_state(state, i == m_children.size() - 1)); -} - -void LabelledStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "LabelledStatement"sv), color_string(state, m_label), format_position(state, source_range()))); - m_labelled_item->dump(child_state(state, true)); -} - -void ClassFieldInitializerStatement::dump(ASTDumpState const&) const -{ - // This should not be dumped as it is never part of an actual AST. - VERIFY_NOT_REACHED(); -} - -void BinaryExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "BinaryExpression"sv), color_op(state, binary_op_to_string(m_op)), format_position(state, source_range()))); - m_lhs->dump(child_state(state, false)); - m_rhs->dump(child_state(state, true)); -} - -void LogicalExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "LogicalExpression"sv), color_op(state, logical_op_to_string(m_op)), format_position(state, source_range()))); - m_lhs->dump(child_state(state, false)); - m_rhs->dump(child_state(state, true)); -} - -void UnaryExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "UnaryExpression"sv), color_op(state, unary_op_to_string(m_op)), format_position(state, source_range()))); - m_lhs->dump(child_state(state, true)); -} - -void CallExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, is(*this) ? "NewExpression"sv : "CallExpression"sv), format_position(state, source_range()))); - bool has_arguments = !arguments().is_empty(); - m_callee->dump(child_state(state, !has_arguments)); - for (size_t i = 0; i < arguments().size(); ++i) - arguments()[i].value->dump(child_state(state, i == arguments().size() - 1)); -} - -void SuperCall::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "SuperCall"sv), format_position(state, source_range()))); - for (size_t i = 0; i < m_arguments.size(); ++i) - m_arguments[i].value->dump(child_state(state, i == m_arguments.size() - 1)); -} - -void ClassDeclaration::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ClassDeclaration"sv), format_position(state, source_range()))); - m_class_expression->dump(child_state(state, true)); -} - -void ClassExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "ClassExpression"sv), color_string(state, name()), format_position(state, source_range()))); - bool has_super = !m_super_class.is_null(); - bool has_elements = !m_elements.is_empty(); - - if (has_super) { - print_node(child_state(state, false), color_label(state, "super class"sv)); - m_super_class->dump(child_state(child_state(state, false), true)); - } - - print_node(child_state(state, !has_elements), color_label(state, "constructor"sv)); - m_constructor->dump(child_state(child_state(state, !has_elements), true)); - - if (has_elements) { - print_node(child_state(state, true), color_label(state, "elements"sv)); - for (size_t i = 0; i < m_elements.size(); ++i) - m_elements[i]->dump(child_state(child_state(state, true), i == m_elements.size() - 1)); - } -} - -void ClassMethod::dump(ASTDumpState const& state) const -{ - StringBuilder description; - description.append(color_node_name(state, "ClassMethod"sv)); - if (is_static()) - description.append(" static"sv); - if (m_kind != Kind::Method) - description.appendff(" {}", color_op(state, class_method_kind_to_string(m_kind))); - description.append(format_position(state, source_range())); - print_node(state, description.to_byte_string()); - m_key->dump(child_state(state, false)); - m_function->dump(child_state(state, true)); -} - -void ClassField::dump(ASTDumpState const& state) const -{ - StringBuilder description; - description.append(color_node_name(state, "ClassField"sv)); - if (is_static()) - description.append(" static"sv); - description.append(format_position(state, source_range())); - print_node(state, description.to_byte_string()); - m_key->dump(child_state(state, !m_initializer)); - if (m_initializer) { - print_node(child_state(state, true), color_label(state, "initializer"sv)); - m_initializer->dump(child_state(child_state(state, true), true)); - } -} - -void StaticInitializer::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "StaticInitializer"sv), format_position(state, source_range()))); - m_function_body->dump(child_state(state, true)); -} - -void StringLiteral::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "StringLiteral"sv), color_string(state, m_value), format_position(state, source_range()))); -} - -void SuperExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "SuperExpression"sv), format_position(state, source_range()))); -} - -void NumericLiteral::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "NumericLiteral"sv), color_number(state, m_value), format_position(state, source_range()))); -} - -void BigIntLiteral::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "BigIntLiteral"sv), color_number(state, m_value), format_position(state, source_range()))); -} - -void BooleanLiteral::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "BooleanLiteral"sv), color_number(state, m_value), format_position(state, source_range()))); -} - -void NullLiteral::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "NullLiteral"sv), format_position(state, source_range()))); -} - -void BindingPattern::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}", color_node_name(state, "BindingPattern"sv), color_op(state, kind == Kind::Array ? "array" : "object"))); - - for (size_t i = 0; i < entries.size(); ++i) { - auto const& entry = entries[i]; - auto entry_state = child_state(state, i == entries.size() - 1); - - if (kind == Kind::Array && entry.is_elision()) { - print_node(entry_state, color_node_name(state, "Elision"sv)); - continue; - } - - StringBuilder label; - label.append("entry"sv); - if (entry.is_rest) - label.append(" (rest)"sv); - print_node(entry_state, color_label(state, label.to_byte_string())); - - bool has_alias = entry.alias.has>() - || entry.alias.has>() - || entry.alias.has>(); - bool has_initializer = entry.initializer; - - if (kind == Kind::Object) { - if (entry.name.has>()) { - print_node(child_state(entry_state, !has_alias && !has_initializer), color_label(state, "name"sv)); - entry.name.get>()->dump(child_state(child_state(entry_state, !has_alias && !has_initializer), true)); - } else if (entry.name.has>()) { - print_node(child_state(entry_state, !has_alias && !has_initializer), color_label(state, "name (computed)"sv)); - entry.name.get>()->dump(child_state(child_state(entry_state, !has_alias && !has_initializer), true)); - } - } - - if (has_alias) { - print_node(child_state(entry_state, !has_initializer), color_label(state, "alias"sv)); - if (entry.alias.has>()) - entry.alias.get>()->dump(child_state(child_state(entry_state, !has_initializer), true)); - else if (entry.alias.has>()) - entry.alias.get>()->dump(child_state(child_state(entry_state, !has_initializer), true)); - else if (entry.alias.has>()) - entry.alias.get>()->dump(child_state(child_state(entry_state, !has_initializer), true)); - } - - if (has_initializer) { - print_node(child_state(entry_state, true), color_label(state, "initializer"sv)); - entry.initializer->dump(child_state(child_state(entry_state, true), true)); - } - } -} - -void FunctionNode::dump(ASTDumpState const& state, ByteString const& class_name, SourceRange const& range) const -{ - StringBuilder description; - description.append(color_node_name(state, class_name)); - auto is_async = m_kind == FunctionKind::Async || m_kind == FunctionKind::AsyncGenerator; - auto is_generator = m_kind == FunctionKind::Generator || m_kind == FunctionKind::AsyncGenerator; - if (is_async) - description.append(" async"sv); - if (is_generator) - description.append('*'); - description.appendff(" {}", color_string(state, name())); - if (m_is_strict_mode) - description.appendff(" {}", color_flag(state, "strict"sv)); - if (m_is_arrow_function) - description.appendff(" {}", color_flag(state, "arrow"sv)); - if (m_parsing_insights.contains_direct_call_to_eval) - description.appendff(" {}", color_flag(state, "direct-eval"sv)); - if (m_parsing_insights.uses_this) - description.appendff(" {}", color_flag(state, "uses-this"sv)); - if (m_parsing_insights.uses_this_from_environment) - description.appendff(" {}", color_flag(state, "uses-this-from-environment"sv)); - if (m_parsing_insights.might_need_arguments_object) - description.appendff(" {}", color_flag(state, "might-need-arguments"sv)); - description.append(format_position(state, range)); - print_node(state, description.to_byte_string()); - - if (!m_parameters->is_empty()) { - print_node(child_state(state, false), color_label(state, "parameters"sv)); - auto params_state = child_state(state, false); - auto const& params = m_parameters->parameters(); - for (size_t i = 0; i < params.size(); ++i) { - auto const& parameter = params[i]; - auto param_state = child_state(params_state, i == params.size() - 1); - bool has_default = parameter.default_value; - if (parameter.is_rest) { - print_node(param_state, color_label(state, "rest"sv)); - parameter.binding.visit( - [&](Identifier const& identifier) { - identifier.dump(child_state(param_state, !has_default)); - }, - [&](BindingPattern const& pattern) { - pattern.dump(child_state(param_state, !has_default)); - }); - } else { - parameter.binding.visit( - [&](Identifier const& identifier) { - identifier.dump(child_state(params_state, i == params.size() - 1)); - }, - [&](BindingPattern const& pattern) { - pattern.dump(child_state(params_state, i == params.size() - 1)); - }); - } - if (has_default) { - print_node(child_state(param_state, true), color_label(state, "default"sv)); - parameter.default_value->dump(child_state(child_state(param_state, true), true)); - } - } - } - - print_node(child_state(state, true), color_label(state, "body"sv)); - body().dump(child_state(child_state(state, true), true)); -} - -void FunctionDeclaration::dump(ASTDumpState const& state) const -{ - FunctionNode::dump(state, class_name(), source_range()); -} - -void FunctionExpression::dump(ASTDumpState const& state) const -{ - FunctionNode::dump(state, class_name(), source_range()); -} - -void YieldExpression::dump(ASTDumpState const& state) const -{ - StringBuilder description; - description.append(color_node_name(state, "YieldExpression"sv)); - if (is_yield_from()) - description.appendff(" {}", color_flag(state, "yield*"sv)); - description.append(format_position(state, source_range())); - print_node(state, description.to_byte_string()); - if (argument()) - argument()->dump(child_state(state, true)); -} - -void AwaitExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "AwaitExpression"sv), format_position(state, source_range()))); - m_argument->dump(child_state(state, true)); -} - -void ReturnStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ReturnStatement"sv), format_position(state, source_range()))); - if (argument()) - argument()->dump(child_state(state, true)); -} - -void IfStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "IfStatement"sv), format_position(state, source_range()))); - bool has_alternate = alternate(); - - print_node(child_state(state, false), color_label(state, "test"sv)); - predicate().dump(child_state(child_state(state, false), true)); - - print_node(child_state(state, !has_alternate), color_label(state, "consequent"sv)); - consequent().dump(child_state(child_state(state, !has_alternate), true)); - - if (has_alternate) { - print_node(child_state(state, true), color_label(state, "alternate"sv)); - alternate()->dump(child_state(child_state(state, true), true)); - } -} - -void WhileStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "WhileStatement"sv), format_position(state, source_range()))); - print_node(child_state(state, false), color_label(state, "test"sv)); - test().dump(child_state(child_state(state, false), true)); - print_node(child_state(state, true), color_label(state, "body"sv)); - body().dump(child_state(child_state(state, true), true)); -} - -void WithStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "WithStatement"sv), format_position(state, source_range()))); - print_node(child_state(state, false), color_label(state, "object"sv)); - object().dump(child_state(child_state(state, false), true)); - print_node(child_state(state, true), color_label(state, "body"sv)); - body().dump(child_state(child_state(state, true), true)); -} - -void DoWhileStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "DoWhileStatement"sv), format_position(state, source_range()))); - print_node(child_state(state, false), color_label(state, "body"sv)); - body().dump(child_state(child_state(state, false), true)); - print_node(child_state(state, true), color_label(state, "test"sv)); - test().dump(child_state(child_state(state, true), true)); -} - -void ForStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ForStatement"sv), format_position(state, source_range()))); - - if (init()) { - print_node(child_state(state, false), color_label(state, "init"sv)); - init()->dump(child_state(child_state(state, false), true)); - } - if (test()) { - print_node(child_state(state, false), color_label(state, "test"sv)); - test()->dump(child_state(child_state(state, false), true)); - } - if (update()) { - print_node(child_state(state, false), color_label(state, "update"sv)); - update()->dump(child_state(child_state(state, false), true)); - } - print_node(child_state(state, true), color_label(state, "body"sv)); - body().dump(child_state(child_state(state, true), true)); -} - -void ForInStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ForInStatement"sv), format_position(state, source_range()))); - print_node(child_state(state, false), color_label(state, "lhs"sv)); - lhs().visit([&](auto& lhs) { lhs->dump(child_state(child_state(state, false), true)); }); - print_node(child_state(state, false), color_label(state, "rhs"sv)); - rhs().dump(child_state(child_state(state, false), true)); - print_node(child_state(state, true), color_label(state, "body"sv)); - body().dump(child_state(child_state(state, true), true)); -} - -void ForOfStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ForOfStatement"sv), format_position(state, source_range()))); - print_node(child_state(state, false), color_label(state, "lhs"sv)); - lhs().visit([&](auto& lhs) { lhs->dump(child_state(child_state(state, false), true)); }); - print_node(child_state(state, false), color_label(state, "rhs"sv)); - rhs().dump(child_state(child_state(state, false), true)); - print_node(child_state(state, true), color_label(state, "body"sv)); - body().dump(child_state(child_state(state, true), true)); -} - -void ForAwaitOfStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ForAwaitOfStatement"sv), format_position(state, source_range()))); - print_node(child_state(state, false), color_label(state, "lhs"sv)); - m_lhs.visit([&](auto& lhs) { lhs->dump(child_state(child_state(state, false), true)); }); - print_node(child_state(state, false), color_label(state, "rhs"sv)); - m_rhs->dump(child_state(child_state(state, false), true)); - print_node(child_state(state, true), color_label(state, "body"sv)); - m_body->dump(child_state(child_state(state, true), true)); -} - -void Identifier::dump(ASTDumpState const& state) const -{ - StringBuilder description; - description.append(color_node_name(state, "Identifier"sv)); - description.appendff(" {}", color_string(state, m_string)); - if (is_local()) { - description.appendff(" {}", color_local(state, local_index())); - } else if (is_global()) { - description.appendff(" {}", color_global(state)); - } - if (m_declaration_kind != DeclarationKind::None) - description.appendff(" {}", color_op(state, declaration_kind_to_string(m_declaration_kind))); - if (m_is_inside_scope_with_eval) - description.appendff(" {}", color_flag(state, "in-eval-scope"sv)); - description.append(format_position(state, source_range())); - print_node(state, description.to_byte_string()); -} - -void PrivateIdentifier::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "PrivateIdentifier"sv), color_string(state, m_string), format_position(state, source_range()))); -} - -void SpreadExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "SpreadExpression"sv), format_position(state, source_range()))); - m_target->dump(child_state(state, true)); -} - -void ThisExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ThisExpression"sv), format_position(state, source_range()))); -} - -void AssignmentExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "AssignmentExpression"sv), color_op(state, assignment_op_to_string(m_op)), format_position(state, source_range()))); - m_lhs.visit([&](auto& lhs) { lhs->dump(child_state(state, false)); }); - m_rhs->dump(child_state(state, true)); -} - -void UpdateExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} ({}, {}){}", color_node_name(state, "UpdateExpression"sv), update_op_to_string(m_op), m_prefixed ? "prefix" : "postfix", format_position(state, source_range()))); - m_argument->dump(child_state(state, true)); -} - -void VariableDeclaration::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "VariableDeclaration"sv), color_op(state, declaration_kind_to_string(m_declaration_kind)), format_position(state, source_range()))); - for (size_t i = 0; i < m_declarations.size(); ++i) - m_declarations[i]->dump(child_state(state, i == m_declarations.size() - 1)); -} - -void UsingDeclaration::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "UsingDeclaration"sv), format_position(state, source_range()))); - for (size_t i = 0; i < m_declarations.size(); ++i) - m_declarations[i]->dump(child_state(state, i == m_declarations.size() - 1)); -} - -void VariableDeclarator::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "VariableDeclarator"sv), format_position(state, source_range()))); - bool has_init = m_init; - m_target.visit([&](auto const& value) { value->dump(child_state(state, !has_init)); }); - if (m_init) - m_init->dump(child_state(state, true)); -} - -void ObjectProperty::dump(ASTDumpState const& state) const -{ - if (m_property_type == Type::Spread) { - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "ObjectProperty"sv), color_op(state, "spread"), format_position(state, source_range()))); - m_key->dump(child_state(state, true)); - } else { - StringBuilder description; - description.append(color_node_name(state, "ObjectProperty"sv)); - if (m_is_method) - description.appendff(" {}", color_op(state, "method")); - else if (m_property_type == Type::Getter) - description.appendff(" {}", color_op(state, "getter")); - else if (m_property_type == Type::Setter) - description.appendff(" {}", color_op(state, "setter")); - description.append(format_position(state, source_range())); - print_node(state, description.to_byte_string()); - m_key->dump(child_state(state, false)); - m_value->dump(child_state(state, true)); - } -} - -void ObjectExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ObjectExpression"sv), format_position(state, source_range()))); - for (size_t i = 0; i < m_properties.size(); ++i) - m_properties[i]->dump(child_state(state, i == m_properties.size() - 1)); -} - -void ExpressionStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ExpressionStatement"sv), format_position(state, source_range()))); - m_expression->dump(child_state(state, true)); -} - -void MemberExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, is_computed() ? "MemberExpression [computed]"sv : "MemberExpression"sv), format_position(state, source_range()))); - m_object->dump(child_state(state, false)); - m_property->dump(child_state(state, true)); -} - -void OptionalChain::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "OptionalChain"sv), format_position(state, source_range()))); - m_base->dump(child_state(state, m_references.is_empty())); - for (size_t i = 0; i < m_references.size(); ++i) { - auto ref_state = child_state(state, i == m_references.size() - 1); - m_references[i].visit( - [&](Call const& call) { - print_node(ref_state, ByteString::formatted("Call({})", call.mode == Mode::Optional ? "optional" : "not optional")); - for (size_t j = 0; j < call.arguments.size(); ++j) - call.arguments[j].value->dump(child_state(ref_state, j == call.arguments.size() - 1)); - }, - [&](ComputedReference const& ref) { - print_node(ref_state, ByteString::formatted("ComputedReference({})", ref.mode == Mode::Optional ? "optional" : "not optional")); - ref.expression->dump(child_state(ref_state, true)); - }, - [&](MemberReference const& ref) { - print_node(ref_state, ByteString::formatted("MemberReference({})", ref.mode == Mode::Optional ? "optional" : "not optional")); - ref.identifier->dump(child_state(ref_state, true)); - }, - [&](PrivateMemberReference const& ref) { - print_node(ref_state, ByteString::formatted("PrivateMemberReference({})", ref.mode == Mode::Optional ? "optional" : "not optional")); - ref.private_identifier->dump(child_state(ref_state, true)); - }); - } -} - -void MetaProperty::dump(ASTDumpState const& state) const -{ - char const* name = nullptr; - switch (m_type) { - case MetaProperty::Type::NewTarget: - name = "new.target"; - break; - case MetaProperty::Type::ImportMeta: - name = "import.meta"; - break; - default: - VERIFY_NOT_REACHED(); - } - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "MetaProperty"sv), name, format_position(state, source_range()))); -} - -void ImportCall::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ImportCall"sv), format_position(state, source_range()))); - m_specifier->dump(child_state(state, !m_options)); - if (m_options) { - print_node(child_state(state, true), color_label(state, "options"sv)); - m_options->dump(child_state(child_state(state, true), true)); - } -} - -void RegExpLiteral::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} /{}/{}{}", color_node_name(state, "RegExpLiteral"sv), pattern(), flags(), format_position(state, source_range()))); -} - -void ArrayExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ArrayExpression"sv), format_position(state, source_range()))); - for (size_t i = 0; i < m_elements.size(); ++i) { - if (m_elements[i]) - m_elements[i]->dump(child_state(state, i == m_elements.size() - 1)); - else - print_node(child_state(state, i == m_elements.size() - 1), ""sv); - } -} - -void TemplateLiteral::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "TemplateLiteral"sv), format_position(state, source_range()))); - for (size_t i = 0; i < m_expressions.size(); ++i) - m_expressions[i]->dump(child_state(state, i == m_expressions.size() - 1)); -} - -void TaggedTemplateLiteral::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "TaggedTemplateLiteral"sv), format_position(state, source_range()))); - print_node(child_state(state, false), color_label(state, "tag"sv)); - m_tag->dump(child_state(child_state(state, false), true)); - print_node(child_state(state, true), color_label(state, "template"sv)); - m_template_literal->dump(child_state(child_state(state, true), true)); -} - -void TryStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "TryStatement"sv), format_position(state, source_range()))); - bool has_handler = handler(); - bool has_finalizer = finalizer(); - - print_node(child_state(state, !has_handler && !has_finalizer), color_label(state, "block"sv)); - block().dump(child_state(child_state(state, !has_handler && !has_finalizer), true)); - - if (has_handler) { - print_node(child_state(state, !has_finalizer), color_label(state, "handler"sv)); - handler()->dump(child_state(child_state(state, !has_finalizer), true)); - } - - if (has_finalizer) { - print_node(child_state(state, true), color_label(state, "finalizer"sv)); - finalizer()->dump(child_state(child_state(state, true), true)); - } -} - -void CatchClause::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "CatchClause"sv), format_position(state, source_range()))); - bool has_parameter = !m_parameter.has(); - if (has_parameter) { - m_parameter.visit( - [&](NonnullRefPtr const& parameter) { - print_node(child_state(state, false), color_label(state, "parameter"sv)); - parameter->dump(child_state(child_state(state, false), true)); - }, - [&](NonnullRefPtr const& pattern) { - print_node(child_state(state, false), color_label(state, "parameter"sv)); - pattern->dump(child_state(child_state(state, false), true)); - }, - [&](Empty) {}); - } - body().dump(child_state(state, true)); -} - -void ThrowStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ThrowStatement"sv), format_position(state, source_range()))); - argument().dump(child_state(state, true)); -} - -void SwitchStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "SwitchStatement"sv), format_position(state, source_range()))); - print_node(child_state(state, m_cases.is_empty()), color_label(state, "discriminant"sv)); - m_discriminant->dump(child_state(child_state(state, m_cases.is_empty()), true)); - for (size_t i = 0; i < m_cases.size(); ++i) - m_cases[i]->dump(child_state(state, i == m_cases.size() - 1)); -} - -void SwitchCase::dump(ASTDumpState const& state) const -{ - if (m_test) { - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "SwitchCase"sv), format_position(state, source_range()))); - print_node(child_state(state, false), color_label(state, "test"sv)); - m_test->dump(child_state(child_state(state, false), true)); - } else { - print_node(state, ByteString::formatted("{} {}{}", color_node_name(state, "SwitchCase"sv), color_op(state, "default"), format_position(state, source_range()))); - } - print_node(child_state(state, true), color_label(state, "consequent"sv)); - auto consequent_state = child_state(child_state(state, true), true); - // Dump children from ScopeNode inline without an extra "BlockStatement" wrapper. - for (size_t i = 0; i < children().size(); ++i) - children()[i]->dump(child_state(consequent_state, i == children().size() - 1)); -} - -void ConditionalExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ConditionalExpression"sv), format_position(state, source_range()))); - print_node(child_state(state, false), color_label(state, "test"sv)); - m_test->dump(child_state(child_state(state, false), true)); - print_node(child_state(state, false), color_label(state, "consequent"sv)); - m_consequent->dump(child_state(child_state(state, false), true)); - print_node(child_state(state, true), color_label(state, "alternate"sv)); - m_alternate->dump(child_state(child_state(state, true), true)); -} - -void SequenceExpression::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "SequenceExpression"sv), format_position(state, source_range()))); - for (size_t i = 0; i < m_expressions.size(); ++i) - m_expressions[i]->dump(child_state(state, i == m_expressions.size() - 1)); -} - -void ExportStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{}{}", color_node_name(state, "ExportStatement"sv), format_position(state, source_range()))); - - auto string_or_null = [](Optional const& string) -> ByteString { - if (!string.has_value()) - return "null"; - return ByteString::formatted("\"{}\"", string); - }; - - bool has_statement = m_statement; - bool has_entries = !m_entries.is_empty(); - - if (has_entries) { - print_node(child_state(state, !has_statement), color_label(state, "entries"sv)); - auto entries_state = child_state(state, !has_statement); - for (size_t i = 0; i < m_entries.size(); ++i) { - auto const& entry = m_entries[i]; - StringBuilder desc; - desc.appendff("ExportName: {}, LocalName: {}", - string_or_null(entry.export_name), - entry.is_module_request() ? ByteString("null") : string_or_null(entry.local_or_import_name)); - if (entry.is_module_request()) - desc.appendff(", ModuleRequest: {}{}", entry.m_module_request->module_specifier, format_assert_clauses(*entry.m_module_request)); - print_node(child_state(entries_state, i == m_entries.size() - 1), desc.to_byte_string()); - } - } - - if (has_statement) { - print_node(child_state(state, true), color_label(state, "statement"sv)); - m_statement->dump(child_state(child_state(state, true), true)); - } -} - -void ImportStatement::dump(ASTDumpState const& state) const -{ - print_node(state, ByteString::formatted("{} from {}{}{}", color_node_name(state, "ImportStatement"sv), color_string(state, m_module_request.module_specifier), format_assert_clauses(m_module_request), format_position(state, source_range()))); - - if (m_entries.is_empty()) - return; - - for (size_t i = 0; i < m_entries.size(); ++i) { - auto const& entry = m_entries[i]; - print_node(child_state(state, i == m_entries.size() - 1), - ByteString::formatted("ImportName: {}, LocalName: {}", entry.import_name, entry.local_name)); - } -} - -String ASTNode::dump_to_string() const -{ - StringBuilder builder; - ASTDumpState state; - state.output = &builder; - dump(state); - return String::from_utf8_with_replacement_character(builder.string_view()); -} - -} diff --git a/Libraries/LibJS/Bytecode/Builtins.cpp b/Libraries/LibJS/Bytecode/Builtins.cpp deleted file mode 100644 index 900e1a4b1c..0000000000 --- a/Libraries/LibJS/Bytecode/Builtins.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2023, Simon Wanner - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace JS::Bytecode { - -Optional get_builtin(MemberExpression const& expression) -{ - if (expression.is_computed() || !expression.object().is_identifier() || !expression.property().is_identifier()) - return {}; - auto base_name = static_cast(expression.object()).string(); - auto property_name = static_cast(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 {}; -} - -} diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index 3f748a1c3b..83d3a363e3 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/Libraries/LibJS/CMakeLists.txt b/Libraries/LibJS/CMakeLists.txt index d8989e5b21..cc24d06070 100644 --- a/Libraries/LibJS/CMakeLists.txt +++ b/Libraries/LibJS/CMakeLists.txt @@ -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 diff --git a/Libraries/LibJS/ModuleEntry.h b/Libraries/LibJS/ModuleEntry.h new file mode 100644 index 0000000000..5433cf2a54 --- /dev/null +++ b/Libraries/LibJS/ModuleEntry.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2026-present, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace JS { + +struct ImportEntry { + Optional import_name; // [[ImportName]]: stored string if Optional is not empty, NAMESPACE-OBJECT otherwise + Utf16FlyString local_name; // [[LocalName]] + Optional m_module_request; // [[ModuleRequest]] + + ImportEntry(Optional 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 export_name; // [[ExportName]] + Optional local_or_import_name; // Either [[ImportName]] or [[LocalName]] + + ExportEntry(Kind export_kind, Optional export_name_, Optional local_or_import_name_) + : kind(export_kind) + , export_name(move(export_name_)) + , local_or_import_name(move(local_or_import_name_)) + { + } + + Optional m_module_request; // [[ModuleRequest]] + + bool is_module_request() const + { + return m_module_request.has_value(); + } + + static ExportEntry indirect_export_entry(ModuleRequest module_request, Optional export_name, Optional 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, {}, {} }; + } +}; + +} diff --git a/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Libraries/LibJS/Runtime/AbstractOperations.cpp index 3cc9f35995..3a5506ee63 100644 --- a/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -952,8 +952,6 @@ ThrowCompletionOr 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(); } } diff --git a/Libraries/LibJS/Runtime/AbstractOperations.h b/Libraries/LibJS/Runtime/AbstractOperations.h index bd935ba283..60774cde18 100644 --- a/Libraries/LibJS/Runtime/AbstractOperations.h +++ b/Libraries/LibJS/Runtime/AbstractOperations.h @@ -28,8 +28,6 @@ namespace JS { -class FunctionDeclaration; - GC::Ref new_declarative_environment(Environment&); JS_API GC::Ref new_object_environment(Object&, bool is_with_environment, Environment*); GC::Ref new_function_environment(ECMAScriptFunctionObject&, Object* new_target); @@ -106,7 +104,6 @@ struct EvalDeclarationData { Vector var_scoped_names; Vector annex_b_candidate_names; - Vector> annex_b_function_declarations; struct LexicalBinding { Utf16FlyString name; diff --git a/Libraries/LibJS/Runtime/ModuleRequest.h b/Libraries/LibJS/Runtime/ModuleRequest.h index 37670741e4..9582ab67c7 100644 --- a/Libraries/LibJS/Runtime/ModuleRequest.h +++ b/Libraries/LibJS/Runtime/ModuleRequest.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include @@ -38,7 +39,17 @@ struct ModuleRequest { { } - ModuleRequest(Utf16FlyString specifier, Vector attributes); + ModuleRequest(Utf16FlyString specifier, Vector 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) { diff --git a/Libraries/LibJS/RustIntegration.h b/Libraries/LibJS/RustIntegration.h index 72c32207db..39bec71a3e 100644 --- a/Libraries/LibJS/RustIntegration.h +++ b/Libraries/LibJS/RustIntegration.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Libraries/LibJS/ScopeRecord.h b/Libraries/LibJS/ScopeRecord.h deleted file mode 100644 index a2ae8f1044..0000000000 --- a/Libraries/LibJS/ScopeRecord.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2026, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -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 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> identifiers; - Optional 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 ast_node; - - HashMap variables; - HashMap identifier_groups; - Vector> functions_to_hoist; - - RefPtr 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> 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; - } -}; - -} diff --git a/Libraries/LibJS/SourceRange.h b/Libraries/LibJS/SourceRange.h index fb8846e66c..28b3ceb388 100644 --- a/Libraries/LibJS/SourceRange.h +++ b/Libraries/LibJS/SourceRange.h @@ -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 { diff --git a/Libraries/LibJS/SourceTextModule.h b/Libraries/LibJS/SourceTextModule.h index 44a23d8174..bc2894ec7c 100644 --- a/Libraries/LibJS/SourceTextModule.h +++ b/Libraries/LibJS/SourceTextModule.h @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace JS { diff --git a/Libraries/LibWeb/Bindings/MainThreadVM.cpp b/Libraries/LibWeb/Bindings/MainThreadVM.cpp index b3dcd414b8..dc8a24479f 100644 --- a/Libraries/LibWeb/Bindings/MainThreadVM.cpp +++ b/Libraries/LibWeb/Bindings/MainThreadVM.cpp @@ -9,7 +9,6 @@ */ #include -#include #include #include #include