1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 09:37:34 +00:00

LibJS: Make parsing import and export entries follow the spec

The big changes are:
- Allow strings as Module{Export, Import}Name
- Properly track declarations in default export statements

However, the spec is a little strange in that it allows function and
class declarations without a name in default export statements.
This is quite hard to fully implement without rewriting more of the
parser so for now this behavior is emulated by faking things with
function and class expressions. See the comments in
parse_export_statement for details on the hacks and where it goes wrong.
This commit is contained in:
davidot 2022-01-16 23:51:28 +01:00 committed by Linus Groh
parent 631bbcd00a
commit aca427fc8c
4 changed files with 278 additions and 73 deletions

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020-2022, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2021, David Tuin <davidot@serenityos.org>
* Copyright (c) 2021-2022, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -252,7 +252,7 @@ struct ModuleRequest {
ModuleRequest() = default;
explicit ModuleRequest(String specifier)
explicit ModuleRequest(FlyString specifier)
: module_specifier(move(specifier))
{
}
@ -262,15 +262,36 @@ struct ModuleRequest {
assertions.empend(move(key), move(value));
}
String module_specifier; // [[Specifier]]
FlyString module_specifier; // [[Specifier]]
Vector<Assertion> assertions; // [[Assertions]]
};
class ImportStatement final : public Statement {
public:
struct ImportEntry {
String import_name;
String local_name;
FlyString import_name;
FlyString local_name;
ImportEntry(FlyString import_name_, FlyString local_name_)
: import_name(move(import_name_))
, local_name(move(local_name_))
{
}
bool is_namespace() const
{
return import_name == "*"sv;
}
ModuleRequest const& module_request() const
{
VERIFY(m_module_request);
return *m_module_request;
}
private:
friend ImportStatement;
ModuleRequest* m_module_request;
};
explicit ImportStatement(SourceRange source_range, ModuleRequest from_module, Vector<ImportEntry> entries = {})
@ -278,13 +299,17 @@ public:
, m_module_request(move(from_module))
, m_entries(move(entries))
{
for (auto& entry : m_entries)
entry.m_module_request = &m_module_request;
}
virtual Completion execute(Interpreter&, GlobalObject&) const override;
virtual void dump(int indent) const override;
bool has_bound_name(StringView name) const;
bool has_bound_name(FlyString const& name) const;
Vector<ImportEntry> const& entries() const { return m_entries; }
ModuleRequest const& module_request() const { return m_module_request; }
private:
ModuleRequest m_module_request;
@ -293,32 +318,53 @@ private:
class ExportStatement final : public Statement {
public:
static FlyString local_name_for_default;
struct ExportEntry {
enum class Kind {
ModuleRequest,
LocalExport
} kind;
// Can always have
String export_name;
FlyString export_name;
// Only if module request
ModuleRequest module_request;
// Has just one of ones below
String local_or_import_name;
FlyString local_or_import_name;
ExportEntry(String export_name, String local_name)
ExportEntry(FlyString export_name, FlyString local_name)
: kind(Kind::LocalExport)
, export_name(move(export_name))
, local_or_import_name(move(local_name))
{
}
ExportEntry(ModuleRequest module_request_, FlyString import_name, FlyString export_name_)
: kind(Kind::ModuleRequest)
, export_name(move(export_name_))
, module_request(move(module_request_))
, local_or_import_name(move(import_name))
{
}
bool is_all_but_default() const
{
return kind == Kind::ModuleRequest && local_or_import_name == "*"sv && export_name.is_null();
}
bool is_all() const
{
return kind == Kind::ModuleRequest && local_or_import_name == "*"sv && !export_name.is_empty();
}
};
explicit ExportStatement(SourceRange source_range, RefPtr<ASTNode> statement, Vector<ExportEntry> entries)
explicit ExportStatement(SourceRange source_range, RefPtr<ASTNode> statement, Vector<ExportEntry> entries, bool is_default_export)
: Statement(source_range)
, m_statement(move(statement))
, m_entries(move(entries))
, m_is_default_export(is_default_export)
{
}
@ -326,14 +372,23 @@ public:
virtual void dump(int indent) const override;
bool has_export(StringView export_name) const;
bool has_export(FlyString const& export_name) const;
bool has_statement() const { return m_statement; }
Vector<ExportEntry> 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;
}
private:
RefPtr<ASTNode> m_statement;
Vector<ExportEntry> m_entries;
bool m_is_default_export { false };
};
class Program final : public ScopeNode {