mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibJS: Move {Import,Export}Entry out of {Import,Export}Statement
By making these be standalone instead of nested structs, we can forward declare them. This will allow us to stop including AST.h in some places.
This commit is contained in:
parent
27e0f56c90
commit
e0916dbb35
Notes:
sideshowbarker
2024-07-17 04:12:27 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/e0916dbb35 Pull-request: https://github.com/SerenityOS/serenity/pull/16153 Reviewed-by: https://github.com/linusg
5 changed files with 106 additions and 107 deletions
|
@ -298,33 +298,33 @@ struct ModuleRequest {
|
|||
Vector<Assertion> assertions; // [[Assertions]]
|
||||
};
|
||||
|
||||
// ImportEntry Record, https://tc39.es/ecma262/#table-importentry-record-fields
|
||||
struct ImportEntry {
|
||||
FlyString import_name; // [[ImportName]] if a String
|
||||
FlyString local_name; // [[LocalName]]
|
||||
bool is_namespace { false }; // [[ImportName]] if `namespace-object`
|
||||
|
||||
ImportEntry(FlyString import_name_, FlyString local_name_, bool is_namespace_ = false)
|
||||
: import_name(move(import_name_))
|
||||
, local_name(move(local_name_))
|
||||
, is_namespace(is_namespace_)
|
||||
{
|
||||
VERIFY(!is_namespace || import_name.is_null());
|
||||
}
|
||||
|
||||
ModuleRequest const& module_request() const
|
||||
{
|
||||
VERIFY(m_module_request);
|
||||
return *m_module_request;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ImportStatement;
|
||||
ModuleRequest* m_module_request; // [[ModuleRequest]]
|
||||
};
|
||||
|
||||
class ImportStatement final : public Statement {
|
||||
public:
|
||||
// ImportEntry Record, https://tc39.es/ecma262/#table-importentry-record-fields
|
||||
struct ImportEntry {
|
||||
FlyString import_name; // [[ImportName]] if a String
|
||||
FlyString local_name; // [[LocalName]]
|
||||
bool is_namespace { false }; // [[ImportName]] if `namespace-object`
|
||||
|
||||
ImportEntry(FlyString import_name_, FlyString local_name_, bool is_namespace_ = false)
|
||||
: import_name(move(import_name_))
|
||||
, local_name(move(local_name_))
|
||||
, is_namespace(is_namespace_)
|
||||
{
|
||||
VERIFY(!is_namespace || import_name.is_null());
|
||||
}
|
||||
|
||||
ModuleRequest const& module_request() const
|
||||
{
|
||||
VERIFY(m_module_request);
|
||||
return *m_module_request;
|
||||
}
|
||||
|
||||
private:
|
||||
friend ImportStatement;
|
||||
ModuleRequest* m_module_request; // [[ModuleRequest]]
|
||||
};
|
||||
|
||||
explicit ImportStatement(SourceRange source_range, ModuleRequest from_module, Vector<ImportEntry> entries = {})
|
||||
: Statement(source_range)
|
||||
, m_module_request(move(from_module))
|
||||
|
@ -348,77 +348,77 @@ private:
|
|||
Vector<ImportEntry> 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;
|
||||
|
||||
FlyString export_name; // [[ExportName]]
|
||||
FlyString local_or_import_name; // Either [[ImportName]] or [[LocalName]]
|
||||
|
||||
ExportEntry(Kind export_kind, FlyString export_name_, FlyString local_or_import_name_)
|
||||
: kind(export_kind)
|
||||
, export_name(move(export_name_))
|
||||
, local_or_import_name(move(local_or_import_name_))
|
||||
{
|
||||
}
|
||||
|
||||
bool is_module_request() const
|
||||
{
|
||||
return m_module_request != nullptr;
|
||||
}
|
||||
|
||||
static ExportEntry indirect_export_entry(ModuleRequest const& module_request, FlyString export_name, FlyString import_name)
|
||||
{
|
||||
ExportEntry entry { Kind::NamedExport, move(export_name), move(import_name) };
|
||||
entry.m_module_request = &module_request;
|
||||
return entry;
|
||||
}
|
||||
|
||||
ModuleRequest const& module_request() const
|
||||
{
|
||||
VERIFY(m_module_request);
|
||||
return *m_module_request;
|
||||
}
|
||||
|
||||
private:
|
||||
ModuleRequest const* m_module_request { nullptr }; // [[ModuleRequest]]
|
||||
friend class ExportStatement;
|
||||
|
||||
public:
|
||||
static ExportEntry named_export(FlyString export_name, FlyString 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(FlyString 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 FlyString local_name_for_default;
|
||||
|
||||
// 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;
|
||||
|
||||
FlyString export_name; // [[ExportName]]
|
||||
FlyString local_or_import_name; // Either [[ImportName]] or [[LocalName]]
|
||||
|
||||
ExportEntry(Kind export_kind, FlyString export_name_, FlyString local_or_import_name_)
|
||||
: kind(export_kind)
|
||||
, export_name(move(export_name_))
|
||||
, local_or_import_name(move(local_or_import_name_))
|
||||
{
|
||||
}
|
||||
|
||||
bool is_module_request() const
|
||||
{
|
||||
return m_module_request != nullptr;
|
||||
}
|
||||
|
||||
static ExportEntry indirect_export_entry(ModuleRequest const& module_request, FlyString export_name, FlyString import_name)
|
||||
{
|
||||
ExportEntry entry { Kind::NamedExport, move(export_name), move(import_name) };
|
||||
entry.m_module_request = &module_request;
|
||||
return entry;
|
||||
}
|
||||
|
||||
ModuleRequest const& module_request() const
|
||||
{
|
||||
VERIFY(m_module_request);
|
||||
return *m_module_request;
|
||||
}
|
||||
|
||||
private:
|
||||
ModuleRequest const* m_module_request { nullptr }; // [[ModuleRequest]]
|
||||
friend ExportStatement;
|
||||
|
||||
public:
|
||||
static ExportEntry named_export(FlyString export_name, FlyString 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(FlyString export_name)
|
||||
{
|
||||
return ExportEntry { Kind::ModuleRequestAll, move(export_name), {} };
|
||||
}
|
||||
|
||||
static ExportEntry empty_named_export()
|
||||
{
|
||||
return ExportEntry { Kind::EmptyNamedExport, {}, {} };
|
||||
}
|
||||
};
|
||||
|
||||
ExportStatement(SourceRange source_range, RefPtr<ASTNode> statement, Vector<ExportEntry> entries, bool is_default_export, ModuleRequest module_request)
|
||||
: Statement(source_range)
|
||||
, m_statement(move(statement))
|
||||
|
|
|
@ -163,6 +163,8 @@ class Environment;
|
|||
class Error;
|
||||
class ErrorType;
|
||||
struct ExecutionContext;
|
||||
struct ExportEntry;
|
||||
class ExportStatement;
|
||||
class Expression;
|
||||
class ForStatement;
|
||||
class FunctionEnvironment;
|
||||
|
@ -172,6 +174,8 @@ class GlobalObject;
|
|||
class HandleImpl;
|
||||
class Heap;
|
||||
class HeapBlock;
|
||||
struct ImportEntry;
|
||||
class ImportStatement;
|
||||
class Interpreter;
|
||||
class Intrinsics;
|
||||
class Module;
|
||||
|
|
|
@ -556,7 +556,7 @@ void Parser::parse_module(Program& program)
|
|||
if (export_statement.has_statement())
|
||||
continue;
|
||||
for (auto& entry : export_statement.entries()) {
|
||||
if (entry.is_module_request() || entry.kind == ExportStatement::ExportEntry::Kind::EmptyNamedExport)
|
||||
if (entry.is_module_request() || entry.kind == ExportEntry::Kind::EmptyNamedExport)
|
||||
return;
|
||||
|
||||
auto const& exported_name = entry.local_or_import_name;
|
||||
|
@ -4162,7 +4162,7 @@ NonnullRefPtr<ImportStatement> Parser::parse_import_statement(Program& program)
|
|||
bool continue_parsing = true;
|
||||
|
||||
struct ImportWithLocation {
|
||||
ImportStatement::ImportEntry entry;
|
||||
ImportEntry entry;
|
||||
Position position;
|
||||
};
|
||||
|
||||
|
@ -4203,7 +4203,7 @@ NonnullRefPtr<ImportStatement> Parser::parse_import_statement(Program& program)
|
|||
if (match_imported_binding()) {
|
||||
auto namespace_position = position();
|
||||
auto namespace_name = consume().value();
|
||||
entries_with_location.append({ ImportStatement::ImportEntry({}, namespace_name, true), namespace_position });
|
||||
entries_with_location.append({ ImportEntry({}, namespace_name, true), namespace_position });
|
||||
} else {
|
||||
syntax_error(String::formatted("Unexpected token: {}", m_state.current_token.name()));
|
||||
}
|
||||
|
@ -4271,7 +4271,7 @@ NonnullRefPtr<ImportStatement> Parser::parse_import_statement(Program& program)
|
|||
|
||||
auto module_request = parse_module_request();
|
||||
|
||||
Vector<ImportStatement::ImportEntry> entries;
|
||||
Vector<ImportEntry> entries;
|
||||
entries.ensure_capacity(entries_with_location.size());
|
||||
|
||||
for (auto& entry : entries_with_location) {
|
||||
|
@ -4293,8 +4293,6 @@ NonnullRefPtr<ImportStatement> Parser::parse_import_statement(Program& program)
|
|||
|
||||
NonnullRefPtr<ExportStatement> Parser::parse_export_statement(Program& program)
|
||||
{
|
||||
using ExportEntry = ExportStatement::ExportEntry;
|
||||
|
||||
// We use the extended syntax which adds:
|
||||
// ExportDeclaration:
|
||||
// export ExportFromClause FromClause [no LineTerminator here] AssertClause ;
|
||||
|
@ -4572,7 +4570,7 @@ NonnullRefPtr<ExportStatement> Parser::parse_export_statement(Program& program)
|
|||
consume_or_insert_semicolon();
|
||||
}
|
||||
|
||||
Vector<ExportStatement::ExportEntry> entries;
|
||||
Vector<ExportEntry> entries;
|
||||
entries.ensure_capacity(entries_with_location.size());
|
||||
|
||||
for (auto& entry : entries_with_location) {
|
||||
|
@ -4582,7 +4580,7 @@ NonnullRefPtr<ExportStatement> Parser::parse_export_statement(Program& program)
|
|||
}
|
||||
|
||||
for (auto& new_entry : entries) {
|
||||
if (new_entry.kind != ExportStatement::ExportEntry::Kind::EmptyNamedExport && new_entry.export_name == entry.entry.export_name)
|
||||
if (new_entry.kind != ExportEntry::Kind::EmptyNamedExport && new_entry.export_name == entry.entry.export_name)
|
||||
syntax_error(String::formatted("Duplicate export with name: '{}'", entry.entry.export_name), entry.position);
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ Result<NonnullGCPtr<SourceTextModule>, Vector<Parser::Error>> SourceTextModule::
|
|||
VERIFY(export_statement.has_statement());
|
||||
|
||||
auto const& entry = export_statement.entries()[0];
|
||||
VERIFY(entry.kind == ExportStatement::ExportEntry::Kind::NamedExport);
|
||||
VERIFY(entry.kind == ExportEntry::Kind::NamedExport);
|
||||
VERIFY(!entry.is_module_request());
|
||||
VERIFY(import_entries.find_if(
|
||||
[&](ImportEntry const& import_entry) {
|
||||
|
@ -182,7 +182,7 @@ Result<NonnullGCPtr<SourceTextModule>, Vector<Parser::Error>> SourceTextModule::
|
|||
|
||||
// Special case, export {} from "module" should add "module" to
|
||||
// required_modules but not any import or export so skip here.
|
||||
if (export_entry.kind == ExportStatement::ExportEntry::Kind::EmptyNamedExport) {
|
||||
if (export_entry.kind == ExportEntry::Kind::EmptyNamedExport) {
|
||||
VERIFY(export_statement.entries().size() == 1);
|
||||
break;
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ Result<NonnullGCPtr<SourceTextModule>, Vector<Parser::Error>> SourceTextModule::
|
|||
}
|
||||
}
|
||||
// b. Else if ee.[[ImportName]] is all-but-default, then
|
||||
else if (export_entry.kind == ExportStatement::ExportEntry::Kind::ModuleRequestAllButDefault) {
|
||||
else if (export_entry.kind == ExportEntry::Kind::ModuleRequestAllButDefault) {
|
||||
// i. Assert: ee.[[ExportName]] is null.
|
||||
VERIFY(export_entry.export_name.is_null());
|
||||
// ii. Append ee to starExportEntries.
|
||||
|
@ -564,7 +564,7 @@ ThrowCompletionOr<ResolvedBinding> SourceTextModule::resolve_export(VM& vm, FlyS
|
|||
auto imported_module = TRY(vm.host_resolve_imported_module(NonnullGCPtr<Module>(*this), entry.module_request()));
|
||||
|
||||
// ii. If e.[[ImportName]] is all, then
|
||||
if (entry.kind == ExportStatement::ExportEntry::Kind::ModuleRequestAll) {
|
||||
if (entry.kind == ExportEntry::Kind::ModuleRequestAll) {
|
||||
// 1. Assert: module does not provide the direct binding for this export.
|
||||
// FIXME: What does this mean? / How do we check this
|
||||
|
||||
|
|
|
@ -20,9 +20,6 @@ class SourceTextModule final : public CyclicModule {
|
|||
JS_CELL(SourceTextModule, CyclicModule);
|
||||
|
||||
public:
|
||||
using ImportEntry = ImportStatement::ImportEntry;
|
||||
using ExportEntry = ExportStatement::ExportEntry;
|
||||
|
||||
static Result<NonnullGCPtr<SourceTextModule>, Vector<Parser::Error>> parse(StringView source_text, Realm&, StringView filename = {}, Script::HostDefined* host_defined = nullptr);
|
||||
|
||||
Program const& parse_node() const { return *m_ecmascript_code; }
|
||||
|
|
Loading…
Reference in a new issue