From 3af8e4b8b2a3c83c04dc41a1ba707e1b7ba256e9 Mon Sep 17 00:00:00 2001 From: hufeng Date: Sun, 17 Jul 2022 15:29:44 +0800 Subject: [PATCH 1/4] Support ecmascript standard module with es2abc Description: Implementation of [ESM] in es2abc Signed-off-by: hufeng Change-Id: I902bdeceab3a337dffa41c3d63adb7b8a3a57737 --- es2panda/BUILD.gn | 7 +- es2panda/binder/binder.cpp | 10 +- es2panda/binder/binder.h | 5 +- es2panda/binder/declaration.h | 121 ++++---- es2panda/binder/module.cpp | 239 ++++++++++++++++ es2panda/binder/module.h | 176 ++++++++++++ es2panda/binder/scope.cpp | 135 +++------ es2panda/binder/scope.h | 70 ++--- es2panda/binder/variable.h | 24 -- es2panda/binder/variableFlags.h | 3 +- es2panda/compiler/base/hoisting.cpp | 14 +- es2panda/compiler/base/lexenv.cpp | 24 +- es2panda/compiler/core/compileQueue.cpp | 6 +- es2panda/compiler/core/emitter.cpp | 164 ++++++++++- es2panda/compiler/core/emitter.h | 18 +- es2panda/compiler/core/moduleContext.cpp | 84 ------ es2panda/compiler/core/moduleContext.h | 39 --- es2panda/compiler/core/pandagen.cpp | 52 ++-- es2panda/compiler/core/pandagen.h | 15 +- es2panda/compiler/core/regScope.cpp | 6 +- .../ir/module/exportDefaultDeclaration.cpp | 6 +- es2panda/ir/statements/classDeclaration.cpp | 14 +- es2panda/parser/parserImpl.cpp | 71 +---- es2panda/parser/parserImpl.h | 82 ++---- es2panda/parser/statementParser.cpp | 269 +++++++++++++++--- es2panda/util/helpers.cpp | 5 +- test262/run_sunspider.py | 16 ++ test262/utils.py | 23 ++ 28 files changed, 1105 insertions(+), 593 deletions(-) create mode 100644 es2panda/binder/module.cpp create mode 100644 es2panda/binder/module.h delete mode 100644 es2panda/compiler/core/moduleContext.cpp delete mode 100644 es2panda/compiler/core/moduleContext.h diff --git a/es2panda/BUILD.gn b/es2panda/BUILD.gn index 82a0d44c8f..a44cbe3429 100644 --- a/es2panda/BUILD.gn +++ b/es2panda/BUILD.gn @@ -19,6 +19,7 @@ es2panda_src = [ "es2panda.cpp", "binder/binder.cpp", "binder/declaration.cpp", + "binder/module.cpp", "binder/scope.cpp", "binder/variable.cpp", "compiler/base/catchTable.cpp", @@ -38,7 +39,6 @@ es2panda_src = [ "compiler/core/function.cpp", "compiler/core/inlineCache.cpp", "compiler/core/labelTarget.cpp", - "compiler/core/moduleContext.cpp", "compiler/core/pandagen.cpp", "compiler/core/regAllocator.cpp", "compiler/core/regScope.cpp", @@ -380,7 +380,10 @@ ohos_static_library("es2panda_lib") { "//third_party/icu/icu4c:static_icuuc", ] - cflags = [ "-Wno-implicit-fallthrough" ] + cflags = [ + "-Wno-c++20-designator", + "-Wno-implicit-fallthrough", + ] } ohos_executable("es2panda") { diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index 09b100fa66..aa97f5e4b7 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -252,7 +253,14 @@ void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl) void Binder::BuildClassDefinition(ir::ClassDefinition *classDef) { if (classDef->Parent()->IsClassDeclaration()) { - ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); + util::StringView className; + if (classDef->Ident()) { + className = classDef->Ident()->Name(); + } else { + ASSERT(scope_->IsModuleScope()); + className = util::StringView("*default*"); + } + ScopeFindResult res = scope_->Find(className); ASSERT(res.variable && res.variable->Declaration()->IsClassDecl()); res.variable->AddFlag(VariableFlags::INITIALIZED); diff --git a/es2panda/binder/binder.h b/es2panda/binder/binder.h index 90f06aebf7..ac24e9a86e 100644 --- a/es2panda/binder/binder.h +++ b/es2panda/binder/binder.h @@ -30,6 +30,7 @@ class ClassDefinition; class Expression; class ForUpdateStatement; class Identifier; +class ImportNamespaceSpecifier; class ScriptFunction; class Statement; class VariableDeclarator; @@ -67,7 +68,7 @@ public: return scope_; } - GlobalScope *TopScope() const + FunctionScope *TopScope() const { return topScope_; } @@ -143,7 +144,7 @@ private: void ResolveReferences(const ir::AstNode *parent); parser::Program *program_ {}; - GlobalScope *topScope_ {}; + FunctionScope *topScope_ {}; Scope *scope_ {}; ArenaVector functionScopes_; ArenaSet functionNames_; diff --git a/es2panda/binder/declaration.h b/es2panda/binder/declaration.h index 1e83a306e8..e143c63db4 100644 --- a/es2panda/binder/declaration.h +++ b/es2panda/binder/declaration.h @@ -32,6 +32,12 @@ namespace panda::es2panda::binder { class Scope; class LocalScope; +enum class DeclModuleStatus { + NONE = 0, + IMPORT, + EXPORT, +}; + #define DECLARE_CLASSES(decl_kind, className) class className; DECLARATION_KINDS(DECLARE_CLASSES) #undef DECLARE_CLASSES @@ -82,18 +88,44 @@ public: return IsLetDecl() || IsConstDecl() || IsClassDecl(); } + void SetModuleStatus(DeclModuleStatus status) + { + moduleStatus_ = status; + } + + bool IsExportedDecl() const + { + return moduleStatus_ == DeclModuleStatus::EXPORT; + } + + bool IsImportedDecl() const + { + return moduleStatus_ == DeclModuleStatus::IMPORT; + } + + bool IsNoneModuleDecl() const + { + return moduleStatus_ == DeclModuleStatus::NONE; + } + protected: - explicit Decl(util::StringView name) : name_(name) {} + explicit Decl(util::StringView name, DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) + : name_(name), moduleStatus_(moduleStatus) + { + } util::StringView name_; + DeclModuleStatus moduleStatus_; const ir::AstNode *node_ {}; }; template class MultiDecl : public Decl { public: - explicit MultiDecl(ArenaAllocator *allocator, util::StringView name) - : Decl(name), declarations_(allocator->Adapter()) + explicit MultiDecl(ArenaAllocator *allocator, + util::StringView name, + DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) + : Decl(name, moduleStatus), declarations_(allocator->Adapter()) { } @@ -152,8 +184,11 @@ public: class FunctionDecl : public MultiDecl { public: - explicit FunctionDecl(ArenaAllocator *allocator, util::StringView name, const ir::AstNode *node) - : MultiDecl(allocator, name) + explicit FunctionDecl(ArenaAllocator *allocator, + util::StringView name, + const ir::AstNode *node, + DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) + : MultiDecl(allocator, name, moduleStatus) { node_ = node; } @@ -206,7 +241,8 @@ public: class VarDecl : public Decl { public: - explicit VarDecl(util::StringView name) : Decl(name) {} + explicit VarDecl(util::StringView name, DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) + : Decl(name, moduleStatus) {} DeclType Type() const override { @@ -216,7 +252,8 @@ public: class LetDecl : public Decl { public: - explicit LetDecl(util::StringView name) : Decl(name) {} + explicit LetDecl(util::StringView name, DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) + : Decl(name, moduleStatus) {} DeclType Type() const override { @@ -226,7 +263,8 @@ public: class ConstDecl : public Decl { public: - explicit ConstDecl(util::StringView name) : Decl(name) {} + explicit ConstDecl(util::StringView name, DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) + : Decl(name, moduleStatus) {} DeclType Type() const override { @@ -236,7 +274,8 @@ public: class ClassDecl : public Decl { public: - explicit ClassDecl(util::StringView name) : Decl(name) {} + explicit ClassDecl(util::StringView name, DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) + : Decl(name, moduleStatus) {} DeclType Type() const override { @@ -254,70 +293,6 @@ public: } }; -class ImportDecl : public Decl { -public: - explicit ImportDecl(util::StringView importName, util::StringView localName) - : Decl(localName), importName_(importName) - { - } - - explicit ImportDecl(util::StringView importName, util::StringView localName, const ir::AstNode *node) - : Decl(localName), importName_(importName) - { - BindNode(node); - } - - const util::StringView &ImportName() const - { - return importName_; - } - - const util::StringView &LocalName() const - { - return name_; - } - - DeclType Type() const override - { - return DeclType::IMPORT; - } - -private: - util::StringView importName_; -}; - -class ExportDecl : public Decl { -public: - explicit ExportDecl(util::StringView exportName, util::StringView localName) - : Decl(localName), exportName_(exportName) - { - } - - explicit ExportDecl(util::StringView exportName, util::StringView localName, const ir::AstNode *node) - : Decl(localName), exportName_(exportName) - { - BindNode(node); - } - - const util::StringView &ExportName() const - { - return exportName_; - } - - const util::StringView &LocalName() const - { - return name_; - } - - DeclType Type() const override - { - return DeclType::EXPORT; - } - -private: - util::StringView exportName_; -}; - } // namespace panda::es2panda::binder #endif diff --git a/es2panda/binder/module.cpp b/es2panda/binder/module.cpp new file mode 100644 index 0000000000..553edeb8fc --- /dev/null +++ b/es2panda/binder/module.cpp @@ -0,0 +1,239 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "module.h" + +#include + +namespace panda::es2panda::binder { + + int SourceTextModuleRecord::AddModuleRequest(const util::StringView source, lexer::SourcePosition sourcePos) + { + ASSERT(!source.Empty()); + int moduleRequestsSize = static_cast(moduleRequestsMap_.size()); + if (moduleRequestsMap_.find(source) == moduleRequestsMap_.end()) { + moduleRequests_.emplace_back(source); + } + auto insertedRes = moduleRequestsMap_.insert( + std::make_pair(source, ModuleRequest(moduleRequestsSize, sourcePos.index)) + ); + return insertedRes.first->second.idx; + } + + void SourceTextModuleRecord::AddImportEntry(const util::StringView importName, + const util::StringView localName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos) + { + auto *importEntry = allocator_->New(pos); + importEntry->importName = importName; + importEntry->localName = localName; + importEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); + ASSERT(!importEntry->importName.Empty()); + ASSERT(!importEntry->localName.Empty()); + ASSERT(importEntry->exportName.Empty()); + ASSERT(importEntry->moduleRequest != -1); + regularImportEntries_.insert(std::make_pair(importEntry->localName, importEntry)); + } + + void SourceTextModuleRecord::AddEmptyImportEntry(const util::StringView moduleRequest, + const lexer::SourcePosition sourcePos) + { + AddModuleRequest(moduleRequest, sourcePos); + } + + void SourceTextModuleRecord::AddStarImportEntry(const ir::AstNode *moduleNode, + const util::StringView localName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos) + { + auto *starImportEntry = allocator_->New(pos); + starImportEntry->moduleNode = moduleNode; + starImportEntry->localName = localName; + starImportEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); + ASSERT(starImportEntry->moduleNode != nullptr); + ASSERT(starImportEntry->importName.Empty()); + ASSERT(!starImportEntry->localName.Empty()); + ASSERT(starImportEntry->exportName.Empty()); + ASSERT(starImportEntry->moduleRequest != -1); + namespaceImportEntries_.push_back(starImportEntry); + } + + void SourceTextModuleRecord::AddLocalExportEntry(const util::StringView exportName, + const util::StringView localName, + const lexer::SourcePosition pos) + { + auto *localExportEntry = allocator_->New(pos); + localExportEntry->exportName = exportName; + localExportEntry->localName = localName; + ASSERT(localExportEntry->importName.Empty()); + ASSERT(!localExportEntry->localName.Empty()); + ASSERT(!localExportEntry->exportName.Empty()); + ASSERT(localExportEntry->moduleRequest == -1); + localExportEntries_.insert(std::make_pair(localExportEntry->localName, localExportEntry)); + } + + void SourceTextModuleRecord::AddIndirectExportEntry(const util::StringView importName, + const util::StringView exportName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos) + { + auto *indirectExportEntry = allocator_->New(pos); + indirectExportEntry->importName = importName; + indirectExportEntry->exportName = exportName; + indirectExportEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); + ASSERT(!indirectExportEntry->importName.Empty()); + ASSERT(indirectExportEntry->localName.Empty()); + ASSERT(!indirectExportEntry->exportName.Empty()); + ASSERT(indirectExportEntry->moduleRequest != -1); + indirectExportEntries_.push_back(indirectExportEntry); + } + + void SourceTextModuleRecord::AddStarExportEntry(const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos) + { + auto *starExportEntry = allocator_->New(pos); + starExportEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); + ASSERT(starExportEntry->importName.Empty()); + ASSERT(starExportEntry->localName.Empty()); + ASSERT(starExportEntry->exportName.Empty()); + ASSERT(starExportEntry->moduleRequest != -1); + starExportEntries_.push_back(starExportEntry); + } + + const SourceTextModuleRecord::Entry *SourceTextModuleRecord::NextDuplicateExportEntry( + const Entry *entry, + const Entry *duplicate, + ArenaMap &exportNameEntries) + { + ASSERT(!entry->exportName.Empty()); + auto insertRes = exportNameEntries.insert(std::make_pair(entry->exportName, entry)); + + // successfully inserted when there has no duplicate entry + if (insertRes.second) { + return duplicate; + } + + // find [entry] has same export name with one of the exportNameEntries + if (duplicate == nullptr) { + // update duplicate entry if pre duplicate is null + duplicate = insertRes.first->second; + } + + // return the entry at the backward position + if (entry->position.index > duplicate->position.index) { + return entry; + } + + return duplicate; + } + + const SourceTextModuleRecord::Entry *SourceTextModuleRecord::SearchDupExport() + { + const SourceTextModuleRecord::Entry *duplicateEntry = nullptr; + ArenaMap exportNameEntries( + allocator_->Adapter()); + + for (auto const &entryUnit : localExportEntries_) { + duplicateEntry = NextDuplicateExportEntry(entryUnit.second, duplicateEntry, exportNameEntries); + } + + for (auto entry : indirectExportEntries_) { + duplicateEntry = NextDuplicateExportEntry(entry, duplicateEntry, exportNameEntries); + } + + return duplicateEntry; + } + + bool SourceTextModuleRecord::ValidateModuleRecordEntries(ModuleScope *moduleScope, + std::string &errorMessage, + lexer::SourcePosition &errorPos) + { + ASSERT(this == moduleScope->GetModuleRecord()); + const SourceTextModuleRecord::Entry *dupExportEntry = SearchDupExport(); + if (dupExportEntry != nullptr) { + errorMessage.append("Duplicate export name of '" + dupExportEntry->exportName.Mutf8() + "'"); + errorPos.index = dupExportEntry->position.index; + errorPos.line = dupExportEntry->position.line; + return false; + } + + for (const auto &entryUnit : localExportEntries_) { + const SourceTextModuleRecord::Entry *e = entryUnit.second; + ASSERT(!e->exportName.Empty()); + if (moduleScope->FindLocal(e->localName) == nullptr && !e->localName.Is("*default*")) { + errorMessage.append("Export name '" + e->localName.Mutf8() + "' is not defined"); + errorPos.index = e->position.index; + errorPos.line = e->position.line; + return false; + } + } + + /* + * Translate implicit indirectExport entry into explicit entry + * e.g. import { x } from 'test.js'; export { x } + * ---> + * import { x } from 'test.js'; export { x } from 'test.js'; + */ + for (auto it = localExportEntries_.begin(); it != localExportEntries_.end();) { + auto exportEntry = it->second; + ASSERT(!exportEntry->localName.Empty()); + auto importEntry = regularImportEntries_.find(exportEntry->localName); + if (importEntry != regularImportEntries_.end()) { + ASSERT(exportEntry->importName.Empty()); + ASSERT(exportEntry->moduleRequest == -1); + ASSERT(!importEntry->second->importName.Empty()); + ASSERT(importEntry->second->moduleRequest != -1); + exportEntry->importName = importEntry->second->importName; + exportEntry->moduleRequest = importEntry->second->moduleRequest; + exportEntry->localName = util::StringView(""); + exportEntry->position = importEntry->second->position; + indirectExportEntries_.push_back(exportEntry); + it = localExportEntries_.erase(it); + continue; + } + ++it; + } + return true; + } + + void SourceTextModuleRecord::SetLocalExportEntriesVariables(ModuleScope *moduleScope) + { + for (auto it = localExportEntries_.begin(); + it != localExportEntries_.end(); + it = localExportEntries_.upper_bound(it->first)) { + moduleScope->SetVariableAsExported(allocator_, it->first); + } + } + + void SourceTextModuleRecord::SetNameSpaceImportInitialized(ModuleScope *moduleScope) + { + for (auto namespaceEntry : namespaceImportEntries_) { + auto *var = moduleScope->FindLocal(namespaceEntry->localName); + ASSERT(var != nullptr); + var->AddFlag(VariableFlags::INITIALIZED); + } + } + + void SourceTextModuleRecord::SetModuleEnvironment(ModuleScope *moduleScope) + { + SetNameSpaceImportInitialized(moduleScope); + SetLocalExportEntriesVariables(moduleScope); + } +} // namespace panda::es2panda::binder \ No newline at end of file diff --git a/es2panda/binder/module.h b/es2panda/binder/module.h new file mode 100644 index 0000000000..be3797c9f3 --- /dev/null +++ b/es2panda/binder/module.h @@ -0,0 +1,176 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_SCOPES_MODULE_H +#define ES2PANDA_COMPILER_SCOPES_MODULE_H + +#include +#include + +namespace panda::es2panda::ir { +class AstNode; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::binder { + +class ModuleScope; + +class SourceTextModuleRecord { + public: + explicit SourceTextModuleRecord(ArenaAllocator *allocator) + : allocator_(allocator), + moduleRequestsMap_(allocator_->Adapter()), + moduleRequests_(allocator_->Adapter()), + localExportEntries_(allocator_->Adapter()), + regularImportEntries_(allocator_->Adapter()), + namespaceImportEntries_(allocator_->Adapter()), + starExportEntries_(allocator_->Adapter()), + indirectExportEntries_(allocator_->Adapter()) + { + } + + ~SourceTextModuleRecord() = default; + NO_COPY_SEMANTIC(SourceTextModuleRecord); + NO_MOVE_SEMANTIC(SourceTextModuleRecord); + + struct Entry { + lexer::SourcePosition position; + const ir::AstNode *moduleNode; + int moduleRequest; + util::StringView exportName; + util::StringView localName; + util::StringView importName; + + explicit Entry(lexer::SourcePosition pos) + : position(pos), + moduleNode(nullptr), + moduleRequest(-1) {} + }; + + struct ModuleRequest { + int idx; + int pos; + ModuleRequest(int idx, int pos) + : idx(idx), pos(pos) {} + }; + + // import x from 'test.js'; + // import {x} from 'test.js'; + // import {x as y} from 'test.js'; + // import defaultExport from 'test.js' + void AddImportEntry(const util::StringView importName, + const util::StringView localName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos); + + // import 'test.js' + // import {} from 'test.js' + // export {} from 'test.js' + void AddEmptyImportEntry(const util::StringView moduleRequest, const lexer::SourcePosition sourcePos); + + // import * as x from 'test.js'; + void AddStarImportEntry(const ir::AstNode *moduleNode, + const util::StringView localName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos); + + // export {x}; + // export {x as y}; + // export VariableStatement + // export Declaration + // export default ... + void AddLocalExportEntry(const util::StringView exportName, + const util::StringView localName, + const lexer::SourcePosition pos); + + // export {x} from 'test.js'; + // export {x as y} from 'test.js'; + // import { x } from 'test.js'; export { x } + void AddIndirectExportEntry(const util::StringView importName, + const util::StringView exportName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos); + + // export * from 'test.js'; + void AddStarExportEntry(const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos); + + bool ValidateModuleRecordEntries(ModuleScope *moduleScope, + std::string &errorMessage, + lexer::SourcePosition &errorPos); + + void SetModuleEnvironment(ModuleScope *moduleScope); + + using ModuleRequestMap = ArenaMap; + using LocalExportEntryMap = ArenaMultiMap; + using RegularImportEntryMap = ArenaMap; + + const ArenaVector &GetModuleRequests() const + { + return moduleRequests_; + } + + const LocalExportEntryMap &GetLocalExportEntries() const + { + return localExportEntries_; + } + + const RegularImportEntryMap &GetRegularImportEntries() const + { + return regularImportEntries_; + } + + const ArenaVector &GetNamespaceImportEntries() const + { + return namespaceImportEntries_; + } + + const ArenaVector &GetStarExportEntries() const + { + return starExportEntries_; + } + + const ArenaVector &GetIndirectExportEntries() const + { + return indirectExportEntries_; + } + + private: + int AddModuleRequest(const util::StringView source, lexer::SourcePosition sourcePos); + void SetLocalExportEntriesVariables(ModuleScope *moduleScope); + void SetNameSpaceImportInitialized(ModuleScope *moduleScope); + + const Entry *SearchDupExport(); + + const Entry *NextDuplicateExportEntry(const Entry *entry, + const Entry *duplicate, + ArenaMap &exportNameEntries); + + ArenaAllocator *allocator_; + ModuleRequestMap moduleRequestsMap_; + ArenaVector moduleRequests_; + LocalExportEntryMap localExportEntries_; + RegularImportEntryMap regularImportEntries_; + ArenaVector namespaceImportEntries_; + ArenaVector starExportEntries_; + ArenaVector indirectExportEntries_; +}; + +} // namespace panda::es2panda::binder +#endif \ No newline at end of file diff --git a/es2panda/binder/scope.cpp b/es2panda/binder/scope.cpp index d4a452d764..012100516a 100644 --- a/es2panda/binder/scope.cpp +++ b/es2panda/binder/scope.cpp @@ -342,15 +342,44 @@ bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl // ModuleScope +void ModuleScope::SetVariableAsExported(ArenaAllocator *allocator, util::StringView localName) +{ + auto res = bindings_.find(localName); + // Since the module's exported [localName] has been validated before, + // [localName] must have a binding now. + ASSERT(res != bindings_.end()); + auto *decl = res->second->Declaration(); + decl->SetModuleStatus(DeclModuleStatus::EXPORT); + VariableFlags flags = res->second->Flags(); + if ((flags & VariableFlags::IMPORT) == 0) { + // re-exported importedName should not be LOCAL_EXPORT + flags |= VariableFlags::LOCAL_EXPORT; + } + res->second = allocator->New(decl, flags); +} + bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension) { switch (newDecl->Type()) { case DeclType::VAR: { - return AddVar(allocator, currentVariable, newDecl); + auto [scope, shadowed] = IterateShadowedVariables( + newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); }); + + if (shadowed) { + return false; + } + return newDecl->IsNoneModuleDecl() ? + AddVar(allocator, currentVariable, newDecl) : + AddVar(allocator, currentVariable, newDecl); } case DeclType::FUNC: { - return AddFunction(allocator, currentVariable, newDecl, extension); + if (currentVariable) { + return false; + } + return newDecl->IsNoneModuleDecl() ? + AddFunction(allocator, currentVariable, newDecl, extension) : + AddFunction(allocator, currentVariable, newDecl, extension); } case DeclType::ENUM: { bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}); @@ -362,109 +391,15 @@ bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl case DeclType::INTERFACE: { return AddTSBinding(allocator, currentVariable, newDecl, VariableFlags::INTERFACE); } - case DeclType::IMPORT: { - return AddImport(allocator, currentVariable, newDecl); - } - case DeclType::EXPORT: { - return true; - } default: { - return AddLexical(allocator, currentVariable, newDecl); - } - } -} - -void ModuleScope::AddImportDecl(const ir::ImportDeclaration *importDecl, ImportDeclList &&decls) -{ - auto res = imports_.emplace_back(importDecl, decls); - - for (auto &decl : res.second) { - decl->BindNode(importDecl); - } -} - -void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl) -{ - decl->BindNode(exportDecl); - - ArenaVector decls(allocator_->Adapter()); - decls.push_back(decl); - - AddExportDecl(exportDecl, std::move(decls)); -} - -void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList &&decls) -{ - auto res = exports_.emplace_back(exportDecl, decls); - - for (auto &decl : res.second) { - decl->BindNode(exportDecl); - } -} - -bool ModuleScope::AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) -{ - if (currentVariable && currentVariable->Declaration()->Type() != DeclType::VAR) { - return false; - } - - if (newDecl->Node()->IsImportNamespaceSpecifier()) { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::READONLY)}); - } else { - auto *variable = allocator->New(newDecl, VariableFlags::NONE); - variable->ExoticName() = newDecl->AsImportDecl()->ImportName(); - bindings_.insert({newDecl->Name(), variable}); - } - - return true; -} - -bool ModuleScope::ExportAnalysis() -{ - std::set exportedNames; - - for (const auto &[exportDecl, decls] : exports_) { - if (exportDecl->IsExportAllDeclaration()) { - const auto *exportAllDecl = exportDecl->AsExportAllDeclaration(); - - if (exportAllDecl->Exported() != nullptr) { - auto result = exportedNames.insert(exportAllDecl->Exported()->Name()); - if (!result.second) { - return false; - } - } - - continue; - } - - if (exportDecl->IsExportNamedDeclaration()) { - const auto *exportNamedDecl = exportDecl->AsExportNamedDeclaration(); - - if (exportNamedDecl->Source()) { - continue; - } - } - - for (const auto *decl : decls) { - binder::Variable *variable = FindLocal(decl->LocalName()); - - if (!variable) { - continue; - } - - auto result = exportedNames.insert(decl->ExportName()); - if (!result.second) { + if (currentVariable) { return false; } - - if (!variable->IsModuleVariable()) { - variable->AddFlag(VariableFlags::LOCAL_EXPORT); - localExports_.insert({variable, decl->ExportName()}); - } + return newDecl->IsNoneModuleDecl() ? + AddLexical(allocator, currentVariable, newDecl) : + AddLexical(allocator, currentVariable, newDecl); } } - - return true; } // LocalScope diff --git a/es2panda/binder/scope.h b/es2panda/binder/scope.h index b8aae76aa6..dc5a46028a 100644 --- a/es2panda/binder/scope.h +++ b/es2panda/binder/scope.h @@ -17,6 +17,7 @@ #define ES2PANDA_COMPILER_SCOPES_SCOPE_H #include +#include #include #include #include @@ -586,74 +587,54 @@ public: [[maybe_unused]] ScriptExtension extension) override; }; -class ModuleScope : public GlobalScope { +class ModuleScope : public FunctionScope { public: - template - using ModuleEntry = ArenaVector>; - using ImportDeclList = ArenaVector; - using ExportDeclList = ArenaVector; - using LocalExportNameMap = ArenaMultiMap; - explicit ModuleScope(ArenaAllocator *allocator) - : GlobalScope(allocator), - allocator_(allocator), - imports_(allocator_->Adapter()), - exports_(allocator_->Adapter()), - localExports_(allocator_->Adapter()) - { - } - - ScopeType Type() const override + : FunctionScope(allocator, nullptr), + moduleRecord_(new SourceTextModuleRecord(allocator)) { - return ScopeType::MODULE; + auto *paramScope = allocator->New(allocator, this); + paramScope_ = paramScope; } - const ModuleEntry &Imports() const + ~ModuleScope() { - return imports_; + delete moduleRecord_; } - const ModuleEntry &Exports() const + ScopeType Type() const override { - return exports_; + return ScopeType::MODULE; } - const LocalExportNameMap &LocalExports() const + SourceTextModuleRecord *GetModuleRecord() const { - return localExports_; + return moduleRecord_; } - void AddImportDecl(const ir::ImportDeclaration *importDecl, ImportDeclList &&decls); - - void AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl); - - void AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList &&decls); + void SetVariableAsExported(ArenaAllocator *allocator, util::StringView localName); bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension) override; - bool ExportAnalysis(); - private: - bool AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); - - ArenaAllocator *allocator_; - ModuleEntry imports_; - ModuleEntry exports_; - LocalExportNameMap localExports_; + SourceTextModuleRecord *moduleRecord_; }; template bool VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { + VariableFlags flags = newDecl->IsNoneModuleDecl() ? VariableFlags::HOIST_VAR : + newDecl->IsImportedDecl() ? VariableFlags::HOIST_VAR | VariableFlags::IMPORT : + VariableFlags::HOIST_VAR | VariableFlags::LOCAL_EXPORT; if (!currentVariable) { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::HOIST_VAR)}); + bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); return true; } switch (currentVariable->Declaration()->Type()) { case DeclType::VAR: { - currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR); + currentVariable->Reset(newDecl, flags); break; } case DeclType::PARAM: @@ -674,19 +655,23 @@ bool VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVari { VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST; + flags = newDecl->IsNoneModuleDecl() ? flags : + newDecl->IsImportedDecl() ? flags | VariableFlags::IMPORT : + flags | VariableFlags::LOCAL_EXPORT; + if (!currentVariable) { bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); return true; } - if (extension != ScriptExtension::JS || IsModuleScope()) { + if (extension != ScriptExtension::JS) { return false; } switch (currentVariable->Declaration()->Type()) { case DeclType::VAR: case DeclType::FUNC: { - currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR); + currentVariable->Reset(newDecl, flags); break; } default: { @@ -709,11 +694,14 @@ bool VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Var template bool VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { + VariableFlags flags = newDecl->IsNoneModuleDecl() ? VariableFlags::NONE : + newDecl->IsImportedDecl() ? VariableFlags::NONE | VariableFlags::IMPORT : + VariableFlags::NONE | VariableFlags::LOCAL_EXPORT; if (currentVariable) { return false; } - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::NONE)}); + bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); return true; } diff --git a/es2panda/binder/variable.h b/es2panda/binder/variable.h index 4302048a8b..36190236d6 100644 --- a/es2panda/binder/variable.h +++ b/es2panda/binder/variable.h @@ -182,31 +182,7 @@ public: return VariableType::MODULE; } - compiler::VReg &ModuleReg() - { - return moduleReg_; - } - - compiler::VReg ModuleReg() const - { - return moduleReg_; - } - - const util::StringView &ExoticName() const - { - return exoticName_; - } - - util::StringView &ExoticName() - { - return exoticName_; - } - void SetLexical([[maybe_unused]] Scope *scope) override; - -private: - compiler::VReg moduleReg_ {}; - util::StringView exoticName_ {}; }; class EnumVariable : public Variable { diff --git a/es2panda/binder/variableFlags.h b/es2panda/binder/variableFlags.h index 9406cf2cfd..d262475ba4 100644 --- a/es2panda/binder/variableFlags.h +++ b/es2panda/binder/variableFlags.h @@ -27,8 +27,6 @@ namespace panda::es2panda::binder { _(CLASS, ClassDecl) \ _(FUNC, FunctionDecl) \ _(PARAM, ParameterDecl) \ - _(IMPORT, ImportDecl) \ - _(EXPORT, ExportDecl) \ /* TS */ \ _(TYPE_ALIAS, TypeAliasDecl) \ _(NAMESPACE, NameSpaceDecl) \ @@ -105,6 +103,7 @@ enum class VariableFlags { COMPUTED_IDENT = 1 << 8, COMPUTED_INDEX = 1 << 9, INDEX_NAME = 1 << 10, + IMPORT = 1 << 11, LOCAL_EXPORT = 1 << 12, INFERED_IN_PATTERN = 1 << 13, REST_ARG = 1 << 14, diff --git a/es2panda/compiler/base/hoisting.cpp b/es2panda/compiler/base/hoisting.cpp index 815bf147a8..c5c143a05f 100644 --- a/es2panda/compiler/base/hoisting.cpp +++ b/es2panda/compiler/base/hoisting.cpp @@ -39,7 +39,12 @@ static void HoistVar(PandaGen *pg, binder::Variable *var, const binder::VarDecl binder::ScopeFindResult result(decl->Name(), scope, 0, var); pg->LoadConst(decl->Node(), Constant::JS_UNDEFINED); - pg->StoreAccToLexEnv(decl->Node(), result, true); + if (decl->IsNoneModuleDecl()) { + pg->StoreAccToLexEnv(decl->Node(), result, true); + } else { + ASSERT(scope->IsModuleScope()); + pg->StoreModuleVariable(decl->Node(), decl->Name()); + } } static void HoistFunction(PandaGen *pg, binder::Variable *var, const binder::FunctionDecl *decl) @@ -59,7 +64,12 @@ static void HoistFunction(PandaGen *pg, binder::Variable *var, const binder::Fun binder::ScopeFindResult result(decl->Name(), scope, 0, var); pg->DefineFunction(decl->Node(), scriptFunction, internalName); - pg->StoreAccToLexEnv(decl->Node(), result, true); + if (decl->IsNoneModuleDecl()) { + pg->StoreAccToLexEnv(decl->Node(), result, true); + } else { + ASSERT(scope->IsModuleScope()); + pg->StoreModuleVariable(decl->Node(), decl->Name()); + } } void Hoisting::Hoist(PandaGen *pg) diff --git a/es2panda/compiler/base/lexenv.cpp b/es2panda/compiler/base/lexenv.cpp index 0ca34ca25e..3db467f021 100644 --- a/es2panda/compiler/base/lexenv.cpp +++ b/es2panda/compiler/base/lexenv.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include namespace panda::es2panda::compiler { @@ -44,7 +43,10 @@ static void CheckConstAssignment(PandaGen *pg, const ir::AstNode *node, binder:: static void ExpandLoadLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result) { pg->LoadLexicalVar(node, result.lexLevel, result.variable->AsLocalVariable()->LexIdx()); - pg->ThrowUndefinedIfHole(node, result.variable->Name()); + const auto *decl = result.variable->Declaration(); + if (decl->IsLetOrConstOrClassDecl()) { + pg->ThrowUndefinedIfHole(node, result.variable->Name()); + } } static void ExpandLoadNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result) @@ -70,21 +72,6 @@ void VirtualLoadVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder: // VirtualStoreVar -static void StoreLocalExport(PandaGen *pg, const ir::AstNode *node, binder::Variable *variable) -{ - if (!variable->HasFlag(binder::VariableFlags::LOCAL_EXPORT) || !pg->Scope()->IsModuleScope()) { - return; - } - - auto range = pg->Scope()->AsModuleScope()->LocalExports().equal_range(variable); - - for (auto it = range.first; it != range.second; ++it) { - if (it->second != "default") { - pg->StoreModuleVar(node, it->second); - } - } -} - static void ExpandStoreLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl) { binder::LocalVariable *local = result.variable->AsLocalVariable(); @@ -107,8 +94,6 @@ static void ExpandStoreLexVar(PandaGen *pg, const ir::AstNode *node, const binde } pg->StoreLexicalVar(node, result.lexLevel, local->LexIdx()); - - StoreLocalExport(pg, node, local); } static void ExpandStoreNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, @@ -127,7 +112,6 @@ static void ExpandStoreNormalVar(PandaGen *pg, const ir::AstNode *node, const bi } pg->StoreAccumulator(node, localReg); - StoreLocalExport(pg, node, local); } void VirtualStoreVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl) diff --git a/es2panda/compiler/core/compileQueue.cpp b/es2panda/compiler/core/compileQueue.cpp index 29460a7b3b..dc826a43f3 100644 --- a/es2panda/compiler/core/compileQueue.cpp +++ b/es2panda/compiler/core/compileQueue.cpp @@ -37,7 +37,11 @@ void CompileJob::Run() FunctionEmitter funcEmitter(&allocator, &pg); funcEmitter.Generate(); - context_->GetEmitter()->AddFunction(&funcEmitter); + auto *emitter = context_->GetEmitter(); + emitter->AddFunction(&funcEmitter); + if (scope_->IsModuleScope()) { + emitter->AddSourceTextModuleRecord(&pg); + } if (dependant_) { dependant_->Signal(); diff --git a/es2panda/compiler/core/emitter.cpp b/es2panda/compiler/core/emitter.cpp index cb117f420f..654daae8f7 100644 --- a/es2panda/compiler/core/emitter.cpp +++ b/es2panda/compiler/core/emitter.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,7 @@ void FunctionEmitter::Generate() GenFunctionCatchTables(); GenFunctionICSize(); GenLiteralBuffers(); + GenSourceTextModuleRecord(); } const ArenaSet &FunctionEmitter::Strings() const @@ -291,6 +293,134 @@ void FunctionEmitter::GenLiteralBuffers() } } +void FunctionEmitter::GenModuleRequests(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto &moduleRequests = moduleRecord->GetModuleRequests(); + panda::pandasm::LiteralArray::Literal moduleSize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(moduleRequests.size())}; + moduleLiteralArray.emplace_back(moduleSize); + for (auto request : moduleRequests) { + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = request.Mutf8()}; + moduleLiteralArray.emplace_back(moduleRequest); + } +} + +void FunctionEmitter::GenRegularImportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto ®ularImportEntries = moduleRecord->GetRegularImportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, + .value_ = static_cast(regularImportEntries.size())}; + moduleLiteralArray.emplace_back(entrySize); + for (auto it = regularImportEntries.begin(); it != regularImportEntries.end(); ++it) { + auto *entry = it->second; + panda::pandasm::LiteralArray::Literal localName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName.Mutf8()}; + moduleLiteralArray.emplace_back(localName); + panda::pandasm::LiteralArray::Literal importName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->importName.Mutf8()}; + moduleLiteralArray.emplace_back(importName); + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequest)}; + moduleLiteralArray.emplace_back(moduleRequest); + } +} + +void FunctionEmitter::GenNamespaceImportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto &namespaceImportEntries = moduleRecord->GetNamespaceImportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, + .value_ = static_cast(namespaceImportEntries.size())}; + moduleLiteralArray.emplace_back(entrySize); + for (const auto *entry : namespaceImportEntries) { + panda::pandasm::LiteralArray::Literal localName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName.Mutf8()}; + moduleLiteralArray.emplace_back(localName); + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequest)}; + moduleLiteralArray.emplace_back(moduleRequest); + } +} + +void FunctionEmitter::GenLocalExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto &localExportEntries = moduleRecord->GetLocalExportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(localExportEntries.size())}; + moduleLiteralArray.emplace_back(entrySize); + for (auto it = localExportEntries.begin(); it != localExportEntries.end(); ++it) { + auto *entry = it->second; + panda::pandasm::LiteralArray::Literal localName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName.Mutf8()}; + moduleLiteralArray.emplace_back(localName); + panda::pandasm::LiteralArray::Literal exportName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->exportName.Mutf8()}; + moduleLiteralArray.emplace_back(exportName); + } +} + +void FunctionEmitter::GenIndirectExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto &indirectExportEntries = moduleRecord->GetIndirectExportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(indirectExportEntries.size())}; + moduleLiteralArray.emplace_back(entrySize); + for (const auto *entry : indirectExportEntries) { + panda::pandasm::LiteralArray::Literal exportName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->exportName.Mutf8()}; + moduleLiteralArray.emplace_back(exportName); + panda::pandasm::LiteralArray::Literal importName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->importName.Mutf8()}; + moduleLiteralArray.emplace_back(importName); + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequest)}; + moduleLiteralArray.emplace_back(moduleRequest); + } +} + +void FunctionEmitter::GenStarExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto &starExportEntries = moduleRecord->GetStarExportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(starExportEntries.size())}; + moduleLiteralArray.emplace_back(entrySize); + for (const auto *entry : starExportEntries) { + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequest)}; + moduleLiteralArray.emplace_back(moduleRequest); + } +} + +void FunctionEmitter::GenSourceTextModuleRecord() +{ + if (!pg_->TopScope()->IsModuleScope()) { + return; + } + + auto *moduleRecord = pg_->TopScope()->AsModuleScope()->GetModuleRecord(); + auto &[idx, array] = literalBuffers_.emplace_back(); + idx = pg_->ModuleBuffIndex(); + + GenModuleRequests(moduleRecord, array); + GenRegularImportEntries(moduleRecord, array); + GenNamespaceImportEntries(moduleRecord, array); + GenLocalExportEntries(moduleRecord, array); + GenIndirectExportEntries(moduleRecord, array); + GenStarExportEntries(moduleRecord, array); +} + void FunctionEmitter::GenSourceFileDebugInfo() { func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()}; @@ -359,7 +489,7 @@ Emitter::Emitter(const CompilerContext *context) prog_->function_table.reserve(context->Binder()->Functions().size()); GenESAnnoatationRecord(); - GenESModuleModeRecord(context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); + GenerateESModuleRecord(context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); } Emitter::~Emitter() @@ -375,20 +505,28 @@ void Emitter::GenESAnnoatationRecord() prog_->record_table.emplace(annotationRecord.name, std::move(annotationRecord)); } -void Emitter::GenESModuleModeRecord(bool isModule) +void Emitter::GenerateESModuleRecord(bool isModule) { - auto modeRecord = panda::pandasm::Record("_ESModuleMode", LANG_EXT); - modeRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC); - - auto modeField = panda::pandasm::Field(LANG_EXT); - modeField.name = "isModule"; - modeField.type = panda::pandasm::Type("u8", 0); - modeField.metadata->SetValue( - panda::pandasm::ScalarValue::Create(static_cast(isModule))); - - modeRecord.field_list.emplace_back(std::move(modeField)); + if (isModule) { + auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT); + ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC); + prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord)); + } +} - prog_->record_table.emplace(modeRecord.name, std::move(modeRecord)); +void Emitter::AddSourceTextModuleRecord(PandaGen *pg) +{ + ASSERT(pg->TopScope()->IsModuleScope()); + auto iter = prog_->record_table.find("_ESModuleRecord"); + if (iter != prog_->record_table.end()) { + auto &rec = iter->second; + auto moduleIdxField = panda::pandasm::Field(LANG_EXT); + moduleIdxField.name = std::string {pg->Binder()->Program()->SourceFile()}; + moduleIdxField.type = panda::pandasm::Type("u32", 0); + moduleIdxField.metadata->SetValue(panda::pandasm::ScalarValue::Create( + static_cast(pg->ModuleBuffIndex()))); + rec.field_list.emplace_back(std::move(moduleIdxField)); + } } void Emitter::AddFunction(FunctionEmitter *func) diff --git a/es2panda/compiler/core/emitter.h b/es2panda/compiler/core/emitter.h index 7054a6d1b1..aa607d8cc0 100644 --- a/es2panda/compiler/core/emitter.h +++ b/es2panda/compiler/core/emitter.h @@ -41,6 +41,7 @@ class Statement; namespace panda::es2panda::binder { class Scope; +class SourceTextModuleRecord; } // namespace panda::es2panda::binder namespace panda::es2panda::compiler { @@ -86,6 +87,20 @@ private: void GenLiteralBuffers(); void GenBufferLiterals(const LiteralBuffer *buff); + void GenModuleRequests(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenRegularImportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenNamespaceImportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenLocalExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenIndirectExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenStarExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenSourceTextModuleRecord(); + const PandaGen *pg_; panda::pandasm::Function *func_ {}; ArenaVector>> literalBuffers_; @@ -100,12 +115,13 @@ public: NO_MOVE_SEMANTIC(Emitter); void AddFunction(FunctionEmitter *func); + void AddSourceTextModuleRecord(PandaGen *pg); static void DumpAsm(const panda::pandasm::Program *prog); panda::pandasm::Program *Finalize(bool dumpDebugInfo); private: void GenESAnnoatationRecord(); - void GenESModuleModeRecord(bool isModule); + void GenerateESModuleRecord(bool isModule); std::mutex m_; panda::pandasm::Program *prog_; diff --git a/es2panda/compiler/core/moduleContext.cpp b/es2panda/compiler/core/moduleContext.cpp deleted file mode 100644 index 272a319c36..0000000000 --- a/es2panda/compiler/core/moduleContext.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (c) 2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "moduleContext.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace panda::es2panda::compiler { -void CompileImports(PandaGen *pg, binder::ModuleScope *scope) -{ - for (const auto &[importDecl, decls] : scope->Imports()) { - pg->ImportModule(importDecl, importDecl->Source()->Str()); - - VReg moduleReg = pg->AllocReg(); - pg->StoreAccumulator(importDecl, moduleReg); - - for (const auto *decl : decls) { - binder::Variable *v = scope->FindLocal(decl->LocalName()); - - if (!v->IsModuleVariable()) { - ASSERT(decl->ImportName() == "*"); - - binder::ScopeFindResult result(decl->LocalName(), scope, 0, v); - pg->StoreAccToLexEnv(decl->Node(), result, true); - } else { - v->AsModuleVariable()->ModuleReg() = moduleReg; - } - } - } -} - -void CompileExports(PandaGen *pg, const binder::ModuleScope *scope) -{ - for (const auto &[exportDecl, decls] : scope->Exports()) { - if (exportDecl->IsExportAllDeclaration()) { - pg->ImportModule(exportDecl, exportDecl->AsExportAllDeclaration()->Source()->Str()); - } else if (exportDecl->IsExportNamedDeclaration() && exportDecl->AsExportNamedDeclaration()->Source()) { - pg->ImportModule(exportDecl, exportDecl->AsExportNamedDeclaration()->Source()->Str()); - } else { - continue; - } - - VReg moduleReg = pg->AllocReg(); - pg->StoreAccumulator(exportDecl, moduleReg); - - if (exportDecl->IsExportAllDeclaration()) { - pg->StoreModuleVar(exportDecl, decls.front()->ExportName()); - continue; - } - - pg->CopyModule(exportDecl, moduleReg); - - for (const auto *decl : decls) { - pg->LoadObjByName(decl->Node(), moduleReg, decl->LocalName()); - pg->StoreModuleVar(decl->Node(), decl->ExportName()); - } - } -} - -void ModuleContext::Compile(PandaGen *pg, binder::ModuleScope *scope) -{ - CompileImports(pg, scope); - CompileExports(pg, scope); -} -} // namespace panda::es2panda::compiler diff --git a/es2panda/compiler/core/moduleContext.h b/es2panda/compiler/core/moduleContext.h deleted file mode 100644 index da15b229fe..0000000000 --- a/es2panda/compiler/core/moduleContext.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ES2PANDA_COMPILER_CORE_MODULE_CONTEXT_H -#define ES2PANDA_COMPILER_CORE_MODULE_CONTEXT_H - -#include - -#include - -namespace panda::es2panda::binder { -class Variable; -class ModuleScope; -} // namespace panda::es2panda::binder - -namespace panda::es2panda::compiler { -class PandaGen; - -class ModuleContext { -public: - ModuleContext() = delete; - - static void Compile(PandaGen *pg, binder::ModuleScope *scope); -}; -} // namespace panda::es2panda::compiler - -#endif diff --git a/es2panda/compiler/core/pandagen.cpp b/es2panda/compiler/core/pandagen.cpp index c98ef1087c..d9b31d1142 100644 --- a/es2panda/compiler/core/pandagen.cpp +++ b/es2panda/compiler/core/pandagen.cpp @@ -185,6 +185,13 @@ int32_t PandaGen::AddLiteralBuffer(LiteralBuffer *buf) return buf->Index(); } +void PandaGen::SetModuleRecordBufferIndex() +{ + if (topScope_->IsModuleScope()) { + moduleBuffIndex_ = context_->NewLiteralIndex(); + } +} + int32_t PandaGen::AddLexicalVarNamesForDebugInfo(ArenaMap &lexicalVars) { auto *buf = NewLiteralBuffer(); @@ -231,7 +238,9 @@ void PandaGen::LoadVar(const ir::Identifier *node, const binder::ScopeFindResult } if (var->IsModuleVariable()) { - LoadModuleVariable(node, var->AsModuleVariable()->ModuleReg(), var->AsModuleVariable()->ExoticName()); + LoadModuleVariable(node, var->Name(), var->HasFlag(binder::VariableFlags::LOCAL_EXPORT)); + if (var->Declaration()->IsLetOrConstOrClassDecl()) + ThrowUndefinedIfHole(node, var->Name()); return; } @@ -260,7 +269,21 @@ void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult & } if (var->IsModuleVariable()) { - ThrowConstAssignment(node, var->Name()); + if (!isDeclaration && var->Declaration()->IsConstDecl()) { + ThrowConstAssignment(node, var->Name()); + return; + } + + if (!isDeclaration && var->Declaration()->IsLetDecl()) { + RegScope rs(this); + VReg valueReg = AllocReg(); + StoreAccumulator(node, valueReg); + LoadModuleVariable(node, var->Name(), true); + ThrowUndefinedIfHole(node, var->Name()); + LoadAccumulator(node, valueReg); + } + + StoreModuleVariable(node, var->Name()); return; } @@ -1381,15 +1404,6 @@ void PandaGen::CloseIterator(const ir::AstNode *node, VReg iter) ra_.Emit(node, iter); } -void PandaGen::ImportModule(const ir::AstNode *node, const util::StringView &name) -{ - /* - * TODO: module - * sa_.Emit(node, name); - * strings_.insert(name); - */ -} - void PandaGen::DefineClassWithBuffer(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, VReg lexenv, VReg base) { @@ -1398,24 +1412,22 @@ void PandaGen::DefineClassWithBuffer(const ir::AstNode *node, const util::String strings_.insert(ctorId); } -void PandaGen::LoadModuleVariable(const ir::AstNode *node, VReg module, const util::StringView &name) +void PandaGen::LoadModuleVariable(const ir::AstNode *node, const util::StringView &name, bool isLocalExport) { - /* - * TODO: module - * ra_.Emit(node, name, module); - * strings_.insert(name); - */ + ra_.Emit(node, name, isLocalExport ? static_cast(1) : static_cast(0)); + strings_.insert(name); } -void PandaGen::StoreModuleVar(const ir::AstNode *node, const util::StringView &name) +void PandaGen::StoreModuleVariable(const ir::AstNode *node, const util::StringView &name) { sa_.Emit(node, name); strings_.insert(name); } -void PandaGen::CopyModule(const ir::AstNode *node, VReg module) +void PandaGen::GetModuleNamespace(const ir::AstNode *node, const util::StringView &name) { - ra_.Emit(node, module); + sa_.Emit(node, name); + strings_.insert(name); } void PandaGen::StSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key) diff --git a/es2panda/compiler/core/pandagen.h b/es2panda/compiler/core/pandagen.h index 842deb1f87..21c0ba0bea 100644 --- a/es2panda/compiler/core/pandagen.h +++ b/es2panda/compiler/core/pandagen.h @@ -174,6 +174,11 @@ public: return buffStorage_; } + int32_t ModuleBuffIndex() const + { + return moduleBuffIndex_; + } + uint32_t IcSize() const { return ic_.Size(); @@ -205,6 +210,8 @@ public: LiteralBuffer *NewLiteralBuffer(); int32_t AddLiteralBuffer(LiteralBuffer *buf); + void SetModuleRecordBufferIndex(); + int32_t AddLexicalVarNamesForDebugInfo(ArenaMap &lexicalMap); void InitializeLexEnv(const ir::AstNode *node, VReg lexEnv); @@ -345,10 +352,9 @@ public: void DefineClassWithBuffer(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, VReg lexenv, VReg base); - void ImportModule(const ir::AstNode *node, const util::StringView &name); - void LoadModuleVariable(const ir::AstNode *node, VReg module, const util::StringView &name); - void StoreModuleVar(const ir::AstNode *node, const util::StringView &name); - void CopyModule(const ir::AstNode *node, VReg module); + void LoadModuleVariable(const ir::AstNode *node, const util::StringView &name, bool isLocalExport); + void StoreModuleVariable(const ir::AstNode *node, const util::StringView &name); + void GetModuleNamespace(const ir::AstNode *node, const util::StringView &name); void StSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key); void LdSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key); @@ -429,6 +435,7 @@ private: RegAllocator ra_; RangeRegAllocator rra_; + int32_t moduleBuffIndex_ {-1}; uint32_t usedRegs_ {0}; uint32_t totalRegs_ {0}; friend class ScopeContext; diff --git a/es2panda/compiler/core/regScope.cpp b/es2panda/compiler/core/regScope.cpp index 6426709aad..aa617cb64c 100644 --- a/es2panda/compiler/core/regScope.cpp +++ b/es2panda/compiler/core/regScope.cpp @@ -16,12 +16,12 @@ #include "regScope.h" #include +#include #include #include #include #include #include -#include namespace panda::es2panda::compiler { @@ -115,10 +115,6 @@ FunctionRegScope::FunctionRegScope(PandaGen *pg) : RegScope(pg), envScope_(pg->A pg_->SetSourceLocationFlag(lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION); pg_->LoadAccFromArgs(pg_->rootNode_); - if (funcScope->IsModuleScope()) { - ModuleContext::Compile(pg_, pg_->scope_->AsModuleScope()); - } - Hoisting::Hoist(pg); pg_->SetSourceLocationFlag(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION); } diff --git a/es2panda/ir/module/exportDefaultDeclaration.cpp b/es2panda/ir/module/exportDefaultDeclaration.cpp index 92dc53cd96..082be0b702 100644 --- a/es2panda/ir/module/exportDefaultDeclaration.cpp +++ b/es2panda/ir/module/exportDefaultDeclaration.cpp @@ -34,7 +34,11 @@ void ExportDefaultDeclaration::Dump(ir::AstDumper *dumper) const void ExportDefaultDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const { decl_->Compile(pg); - pg->StoreModuleVar(this, "default"); + if (!decl_->IsFunctionDeclaration() && !decl_->IsClassDeclaration()) { + // export default without [Function Declaration] & [Class Declaration] + // is [ExportAssignment]. e.g. export default 42 (42 be exported as [default]) + pg->StoreModuleVariable(this, "*default*"); + } } checker::Type *ExportDefaultDeclaration::Check([[maybe_unused]] checker::Checker *checker) const diff --git a/es2panda/ir/statements/classDeclaration.cpp b/es2panda/ir/statements/classDeclaration.cpp index 0964fcf99a..672d154dbc 100644 --- a/es2panda/ir/statements/classDeclaration.cpp +++ b/es2panda/ir/statements/classDeclaration.cpp @@ -16,10 +16,12 @@ #include "classDeclaration.h" #include +#include #include #include #include #include +#include namespace panda::es2panda::ir { @@ -39,9 +41,15 @@ void ClassDeclaration::Dump(ir::AstDumper *dumper) const void ClassDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - auto lref = compiler::LReference::CreateLRef(pg, def_->Ident(), true); - def_->Compile(pg); - lref.SetValue(); + if (def_->Ident()) { + auto lref = compiler::LReference::CreateLRef(pg, def_->Ident(), true); + def_->Compile(pg); + lref.SetValue(); + } else { + ASSERT(this->Parent()->IsExportDefaultDeclaration() && pg->Scope()->IsModuleScope()); + def_->Compile(pg); + pg->StoreModuleVariable(def_, util::StringView("*default*")); + } } checker::Type *ClassDeclaration::Check([[maybe_unused]] checker::Checker *checker) const diff --git a/es2panda/parser/parserImpl.cpp b/es2panda/parser/parserImpl.cpp index 6ecfc77b84..82886c7942 100644 --- a/es2panda/parser/parserImpl.cpp +++ b/es2panda/parser/parserImpl.cpp @@ -122,11 +122,6 @@ Program ParserImpl::ParseModule(const std::string &fileName, const std::string & context_.Status() |= (ParserStatus::MODULE); ParseProgram(ScriptKind::MODULE); - - if (!Binder()->TopScope()->AsModuleScope()->ExportAnalysis()) { - ThrowSyntaxError("Invalid exported binding"); - } - return std::move(program_); } @@ -142,6 +137,18 @@ void ParserImpl::ParseProgram(ScriptKind kind) Binder()->GetScope()->BindNode(blockStmt); blockStmt->SetRange({startLoc, lexer_->GetToken().End()}); + if (kind == ScriptKind::MODULE) { + auto *moduleRecord = GetSourceTextModuleRecord(); + ASSERT(moduleRecord != nullptr); + std::string errorMessage = ""; + lexer::SourcePosition errorPos; + if (!moduleRecord->ValidateModuleRecordEntries(Binder()->TopScope()->AsModuleScope(), + errorMessage, errorPos)) { + ThrowSyntaxError(errorMessage.c_str(), errorPos); + } + moduleRecord->SetModuleEnvironment(Binder()->TopScope()->AsModuleScope()); + } + program_.SetAst(blockStmt); Binder()->IdentifierAnalysis(); } @@ -3250,58 +3257,4 @@ ScriptExtension ParserImpl::Extension() const return program_.Extension(); } -void ExportDeclarationContext::BindExportDecl(const ir::AstNode *exportDecl) -{ - if (!binder_) { - return; - } - - binder::ModuleScope::ExportDeclList declList(Allocator()->Adapter()); - - if (exportDecl->IsExportDefaultDeclaration()) { - const auto *decl = exportDecl->AsExportDefaultDeclaration(); - const auto *rhs = decl->Decl(); - - if (binder_->GetScope()->Bindings().size() == savedBindings_.size()) { - if (rhs->IsFunctionDeclaration()) { - binder_->AddDecl(rhs->Start(), binder_->Allocator(), - util::StringView(DEFAULT_EXPORT), - rhs->AsFunctionDeclaration()->Function()); - } else { - binder_->AddDecl(rhs->Start(), util::StringView(DEFAULT_EXPORT)); - } - } - } - - for (const auto &[name, variable] : binder_->GetScope()->Bindings()) { - if (savedBindings_.find(name) != savedBindings_.end()) { - continue; - } - - util::StringView exportName(exportDecl->IsExportDefaultDeclaration() ? "default" : name); - - variable->AddFlag(binder::VariableFlags::LOCAL_EXPORT); - auto *decl = binder_->AddDecl(variable->Declaration()->Node()->Start(), exportName, name); - declList.push_back(decl); - } - - auto *moduleScope = binder_->GetScope()->AsModuleScope(); - moduleScope->AddExportDecl(exportDecl, std::move(declList)); -} - -void ImportDeclarationContext::BindImportDecl(const ir::ImportDeclaration *importDecl) -{ - binder::ModuleScope::ImportDeclList declList(Allocator()->Adapter()); - - for (const auto &[name, variable] : binder_->GetScope()->Bindings()) { - if (savedBindings_.find(name) != savedBindings_.end()) { - continue; - } - - declList.push_back(variable->Declaration()->AsImportDecl()); - } - - binder_->GetScope()->AsModuleScope()->AddImportDecl(importDecl, std::move(declList)); -} - } // namespace panda::es2panda::parser diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index 9a4d37a1e9..dd4ab934c5 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -117,6 +117,10 @@ enum class MethodDefinitionKind; enum class ModifierFlags; } // namespace panda::es2panda::ir +namespace panda::es2panda::binder { +class SourceTextModuleRecord; +} // namespace panda::es2panda::binder + namespace panda::es2panda::parser { class Program; @@ -394,6 +398,15 @@ private: bool IsLabelFollowedByIterationStatement(); + void AddImportEntryItem(const ir::StringLiteral *source, const ArenaVector *specifiers); + void AddExportNamedEntryItem(const ArenaVector &specifiers, const ir::StringLiteral *source); + void AddExportStarEntryItem(const lexer::SourcePosition &startLoc, + const ir::StringLiteral *source, + const ir::Identifier *exported); + void AddExportDefaultEntryItem(const ir::AstNode *declNode); + void AddExportLocalEntryItem(const ir::Statement *declNode); + binder::SourceTextModuleRecord *GetSourceTextModuleRecord(); + bool ParseDirective(ArenaVector *statements); void ParseDirectivePrologue(ArenaVector *statements); ArenaVector ParseStatementList(StatementParsingFlags flags = StatementParsingFlags::ALLOW_LEXICAL); @@ -422,7 +435,7 @@ private: ir::Statement *ParseFunctionStatement(StatementParsingFlags flags, bool isDeclare); ir::FunctionDeclaration *ParseFunctionDeclaration(bool canBeAnonymous = false, ParserStatus newStatus = ParserStatus::NO_OPTS, - bool isDeclare = false); + bool isDeclare = false, bool isExported = false); ir::Statement *ParseExportDeclaration(StatementParsingFlags flags, ArenaVector &&decorators); std::tuple ParseForInOf( ir::Expression *leftNode, ExpressionParseFlags exprFlags, bool isAwait); @@ -438,8 +451,11 @@ private: ir::ReturnStatement *ParseReturnStatement(); ir::ClassDeclaration *ParseClassStatement(StatementParsingFlags flags, bool isDeclare, ArenaVector &&decorators, bool isAbstract = false); - ir::ClassDeclaration *ParseClassDeclaration(bool idRequired, ArenaVector &&decorators, - bool isDeclare = false, bool isAbstract = false); + ir::ClassDeclaration *ParseClassDeclaration(bool idRequired, + ArenaVector &&decorators, + bool isDeclare = false, + bool isAbstract = false, + bool isExported = false); ir::TSTypeAliasDeclaration *ParseTsTypeAliasDeclaration(bool isDeclare); ir::TSEnumDeclaration *ParseEnumMembers(ir::Identifier *key, const lexer::SourcePosition &enumStart, bool isConst); ir::TSEnumDeclaration *ParseEnumDeclaration(bool isConst = false); @@ -453,13 +469,21 @@ private: void ValidateDeclaratorId(); ir::VariableDeclarator *ParseVariableDeclaratorInitializer(ir::Expression *init, VariableParsingFlags flags, const lexer::SourcePosition &startLoc, bool isDeclare); - ir::VariableDeclarator *ParseVariableDeclarator(VariableParsingFlags flags, bool isDeclare); + ir::VariableDeclarator *ParseVariableDeclarator(VariableParsingFlags flags, + bool isDeclare, bool isExported = false); ir::Statement *ParseVariableDeclaration(VariableParsingFlags flags = VariableParsingFlags::NO_OPTS, - bool isDeclare = false); + bool isDeclare = false, bool isExported = false); ir::WhileStatement *ParseWhileStatement(); ir::VariableDeclaration *ParseContextualLet(VariableParsingFlags flags, StatementParsingFlags stmFlags = StatementParsingFlags::ALLOW_LEXICAL, bool isDeclare = false); + util::StringView GetNamespaceExportInternalName() + { + std::string name = "=ens" + std::to_string(namespaceExportCount_++); + util::UString internalName(name, Allocator()); + return internalName.View(); + } + ArenaAllocator *Allocator() const { return program_.Allocator(); @@ -477,6 +501,7 @@ private: Program program_; ParserContext context_; lexer::Lexer *lexer_ {nullptr}; + size_t namespaceExportCount_ {0}; }; template @@ -639,53 +664,6 @@ private: } }; -class SavedBindingsContext { -public: - explicit SavedBindingsContext(binder::Binder *binder) - : binder_(binder), savedBindings_(binder_->GetScope()->Bindings()) - { - } - NO_COPY_SEMANTIC(SavedBindingsContext); - NO_MOVE_SEMANTIC(SavedBindingsContext); - ~SavedBindingsContext() = default; - -protected: - ArenaAllocator *Allocator() const - { - return binder_->Allocator(); - } - - binder::Binder *binder_; - binder::VariableMap savedBindings_; -}; - -class ExportDeclarationContext : public SavedBindingsContext { -public: - explicit ExportDeclarationContext(binder::Binder *binder) : SavedBindingsContext(binder) {} - NO_COPY_SEMANTIC(ExportDeclarationContext); - NO_MOVE_SEMANTIC(ExportDeclarationContext); - ~ExportDeclarationContext() = default; - - void BindExportDecl(const ir::AstNode *exportDecl); - -protected: - static constexpr std::string_view DEFAULT_EXPORT = "*default*"; -}; - -class ImportDeclarationContext : public SavedBindingsContext { -public: - explicit ImportDeclarationContext(binder::Binder *binder) : SavedBindingsContext(binder) {} - - NO_COPY_SEMANTIC(ImportDeclarationContext); - NO_MOVE_SEMANTIC(ImportDeclarationContext); - - ~ImportDeclarationContext() = default; - - void BindImportDecl(const ir::ImportDeclaration *importDecl); - -private: -}; - } // namespace panda::es2panda::parser #endif diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index 7a0df02cc9..b9489ece06 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -516,13 +516,18 @@ ir::ClassDeclaration *ParserImpl::ParseClassStatement(StatementParsingFlags flag } ir::ClassDeclaration *ParserImpl::ParseClassDeclaration(bool idRequired, ArenaVector &&decorators, - bool isDeclare, bool isAbstract) + bool isDeclare, bool isAbstract, bool isExported) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ir::ClassDefinition *classDefinition = ParseClassDefinition(true, idRequired, isDeclare, isAbstract); auto *decl = - Binder()->AddDecl(classDefinition->Ident()->Start(), classDefinition->Ident()->Name()); + Binder()->AddDecl(classDefinition->Ident() == nullptr ? + startLoc : classDefinition->Ident()->Start(), + classDefinition->Ident() == nullptr ? + util::StringView("*default*") : classDefinition->Ident()->Name(), + isExported ? + binder::DeclModuleStatus::EXPORT : binder::DeclModuleStatus::NONE); decl->BindNode(classDefinition); lexer::SourcePosition endLoc = classDefinition->End(); @@ -955,7 +960,7 @@ ir::DoWhileStatement *ParserImpl::ParseDoWhileStatement() } ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymous, ParserStatus newStatus, - bool isDeclare) + bool isDeclare, bool isExported) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); @@ -971,6 +976,7 @@ ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymou context_.Status() = savedStatus; + // e.g. export default function () {} if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT && lexer_->GetToken().Type() != lexer::TokenType::KEYW_AWAIT) { if (canBeAnonymous) { @@ -979,6 +985,12 @@ ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymou auto *funcDecl = AllocNode(func); funcDecl->SetRange(func->Range()); + Binder()->AddDecl(startLoc, + Allocator(), + util::StringView("*default*"), + func, + isExported ? + binder::DeclModuleStatus::EXPORT : binder::DeclModuleStatus::NONE); return funcDecl; } @@ -1004,7 +1016,12 @@ ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymou funcDecl->SetRange(func->Range()); if (!func->IsOverload()) { - Binder()->AddDecl(identNode->Start(), Allocator(), ident, func); + Binder()->AddDecl(identNode->Start(), + Allocator(), + ident, + func, + isExported ? + binder::DeclModuleStatus::EXPORT : binder::DeclModuleStatus::NONE); } else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); } @@ -1745,7 +1762,8 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclaratorInitializer(ir::Expre return declarator; } -ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags flags, bool isDeclare) +ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags flags, + bool isDeclare, bool isExported) { ir::Expression *init = nullptr; lexer::SourcePosition startLoc = lexer_->GetToken().Start(); @@ -1807,12 +1825,15 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags for (const auto *binding : bindings) { binder::Decl *decl = nullptr; + binder::DeclModuleStatus moduleDeclkind + = isExported ? binder::DeclModuleStatus::EXPORT : binder::DeclModuleStatus::NONE; + if (flags & VariableParsingFlags::VAR) { - decl = Binder()->AddDecl(startLoc, binding->Name()); + decl = Binder()->AddDecl(startLoc, binding->Name(), moduleDeclkind); } else if (flags & VariableParsingFlags::LET) { - decl = Binder()->AddDecl(startLoc, binding->Name()); + decl = Binder()->AddDecl(startLoc, binding->Name(), moduleDeclkind); } else { - decl = Binder()->AddDecl(startLoc, binding->Name()); + decl = Binder()->AddDecl(startLoc, binding->Name(), moduleDeclkind); } decl->BindNode(init); @@ -1821,7 +1842,7 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags return declarator; } -ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, bool isDeclare) +ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, bool isDeclare, bool isExported) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); @@ -1844,7 +1865,7 @@ ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, ArenaVector declarators(Allocator()->Adapter()); while (true) { - ir::VariableDeclarator *declarator = ParseVariableDeclarator(flags, isDeclare); + ir::VariableDeclarator *declarator = ParseVariableDeclarator(flags, isDeclare, isExported); declarators.push_back(declarator); @@ -1896,6 +1917,163 @@ ir::WhileStatement *ParserImpl::ParseWhileStatement() return whileStatement; } +binder::SourceTextModuleRecord *ParserImpl::GetSourceTextModuleRecord() +{ + return Binder()->TopScope()->AsModuleScope()->GetModuleRecord(); +} + +void ParserImpl::AddImportEntryItem(const ir::StringLiteral *source, const ArenaVector *specifiers) +{ + ASSERT(source != nullptr); + auto moduleRecord = GetSourceTextModuleRecord(); + + if (specifiers == nullptr || specifiers->empty()) { + moduleRecord->AddEmptyImportEntry(source->Str(), source->Start()); + return; + } + + for (auto *it : *specifiers) { + switch(it->Type()) { + case ir::AstNodeType::IMPORT_DEFAULT_SPECIFIER: { + auto importDefault = it->AsImportDefaultSpecifier(); + auto defaultString = util::StringView("default"); + moduleRecord->AddImportEntry(defaultString, + importDefault->Local()->Name(), + source->Str(), + importDefault->Start(), + source->Start()); + break; + } + case ir::AstNodeType::IMPORT_NAMESPACE_SPECIFIER: { + auto namespaceSpecifier = it->AsImportNamespaceSpecifier(); + moduleRecord->AddStarImportEntry(it, + namespaceSpecifier->Local()->Name(), + source->Str(), + namespaceSpecifier->Start(), + source->Start()); + break; + } + case ir::AstNodeType::IMPORT_SPECIFIER: { + auto importSpecifier = it->AsImportSpecifier(); + moduleRecord->AddImportEntry(importSpecifier->Imported()->Name(), + importSpecifier->Local()->Name(), + source->Str(), + importSpecifier->Start(), + source->Start()); + break; + } + default: { + ThrowSyntaxError("Unexpected astNode type", it->Start()); + } + } + } +} + +void ParserImpl::AddExportNamedEntryItem(const ArenaVector &specifiers, + const ir::StringLiteral *source) +{ + auto moduleRecord = GetSourceTextModuleRecord(); + ASSERT(moduleRecord != nullptr); + if (source) { + if (specifiers.empty()) { + moduleRecord->AddEmptyImportEntry(source->Str(), source->Start()); + } + + for (auto *it : specifiers) { + auto exportSpecifier = it->AsExportSpecifier(); + moduleRecord->AddIndirectExportEntry(exportSpecifier->Local()->Name(), + exportSpecifier->Exported()->Name(), + source->Str(), + exportSpecifier->Start(), + source->Start()); + } + } else { + for (auto *it : specifiers) { + auto exportSpecifier = it->AsExportSpecifier(); + moduleRecord->AddLocalExportEntry(exportSpecifier->Exported()->Name(), + exportSpecifier->Local()->Name(), + exportSpecifier->Start()); + } + } +} + +void ParserImpl::AddExportStarEntryItem(const lexer::SourcePosition &startLoc, + const ir::StringLiteral *source, + const ir::Identifier *exported) +{ + ASSERT(source != nullptr); + auto moduleRecord = GetSourceTextModuleRecord(); + + if (exported != nullptr) { + /* Transform [NamespaceExport] into [NamespaceImport] & [LocalExport] + * e.g. export * as ns from 'test.js' + * ---> + * import * as [internalName] from 'test.js' + * export { [inter] as ns } + */ + auto namespaceExportInternalName = GetNamespaceExportInternalName(); + Binder()->AddDecl(startLoc, namespaceExportInternalName, binder::DeclModuleStatus::NONE); + moduleRecord->AddStarImportEntry(exported, namespaceExportInternalName, source->Str(), + lexer::SourcePosition(), source->Start()); + moduleRecord->AddLocalExportEntry(exported->Name(), namespaceExportInternalName, exported->Start()); + } + + moduleRecord->AddStarExportEntry(source->Str(), startLoc, source->Start()); +} + +void ParserImpl::AddExportDefaultEntryItem(const ir::AstNode *declNode) +{ + ASSERT(declNode != nullptr); + if (declNode->IsTSInterfaceDeclaration()) { + return; + } + auto moduleRecord = GetSourceTextModuleRecord(); + auto exportName = util::StringView("default"); + util::StringView localName; + if (declNode->IsFunctionDeclaration() || declNode->IsClassDeclaration()) { + const ir::Identifier *name = declNode->IsFunctionDeclaration() ? + declNode->AsFunctionDeclaration()->Function()->Id() : + declNode->AsClassDeclaration()->Definition()->Ident(); + localName = name == nullptr ? util::StringView("*default*") : name->Name(); + } + if (declNode->IsExpression()) { + localName = util::StringView("*default*"); + } + ASSERT(!localName.Empty()); + moduleRecord->AddLocalExportEntry(exportName, + localName, + declNode->Start()); +} + +void ParserImpl::AddExportLocalEntryItem(const ir::Statement *declNode) +{ + ASSERT(declNode != nullptr); + auto moduleRecord = GetSourceTextModuleRecord(); + if (declNode->IsVariableDeclaration()) { + auto declarators = declNode->AsVariableDeclaration()->Declarators(); + for (auto *decl : declarators) { + std::vector bindings = util::Helpers::CollectBindingNames(decl->Id()); + for (const auto *binding : bindings) { + moduleRecord->AddLocalExportEntry(binding->Name(), + binding->Name(), + binding->Start()); + } + } + } + if (declNode->IsFunctionDeclaration() || declNode->IsClassDeclaration()) { + auto name = declNode->IsFunctionDeclaration() ? + declNode->AsFunctionDeclaration()->Function()->Id() : + declNode->AsClassDeclaration()->Definition()->Ident(); + if (name == nullptr) { + ThrowSyntaxError("A class or function declaration without the default modifier mush have a name.", + declNode->Start()); + } + moduleRecord->AddLocalExportEntry(name->Name(), + name->Name(), + name->Start()); + } +} + ir::ExportDefaultDeclaration *ParserImpl::ParseExportDefaultDeclaration(const lexer::SourcePosition &startLoc, ArenaVector decorators, bool isExportEquals) @@ -1910,27 +2088,32 @@ ir::ExportDefaultDeclaration *ParserImpl::ParseExportDefaultDeclaration(const le ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); } - ExportDeclarationContext exportDeclCtx(Binder()); - if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_FUNCTION) { - declNode = ParseFunctionDeclaration(true); + declNode = ParseFunctionDeclaration(true, ParserStatus::NO_OPTS, false, true); } else if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_CLASS) { - declNode = ParseClassDeclaration(false, std::move(decorators)); + declNode = ParseClassDeclaration(false, std::move(decorators), false, false, true); } else if (lexer_->GetToken().IsAsyncModifier()) { lexer_->NextToken(); // eat `async` keyword - declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); + declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION, false, true); } else if (Extension() == ScriptExtension::TS && lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_INTERFACE) { declNode = ParseTsInterfaceDeclaration(); } else { declNode = ParseExpression(); + Binder()->AddDecl(declNode->Start(), + util::StringView("*default*"), + binder::DeclModuleStatus::EXPORT); eatSemicolon = true; } + // record default export entry + if (!isExportEquals) { + AddExportDefaultEntryItem(declNode); + } + lexer::SourcePosition endLoc = declNode->End(); auto *exportDeclaration = AllocNode(declNode, isExportEquals); exportDeclaration->SetRange({startLoc, endLoc}); - exportDeclCtx.BindExportDecl(exportDeclaration); if (eatSemicolon) { ConsumeSemicolon(exportDeclaration); @@ -1968,10 +2151,11 @@ ir::ExportAllDeclaration *ParserImpl::ParseExportAllDeclaration(const lexer::Sou ir::StringLiteral *source = ParseFromClause(); lexer::SourcePosition endLoc = source->End(); + // record export star entry + AddExportStarEntryItem(startLoc, source, exported); + auto *exportDeclaration = AllocNode(source, exported); exportDeclaration->SetRange({startLoc, endLoc}); - auto *decl = Binder()->AddDecl(startLoc, exported ? exported->Name() : "*", "*"); - Binder()->GetScope()->AsModuleScope()->AddExportDecl(exportDeclaration, decl); ConsumeSemicolon(exportDeclaration); @@ -1983,7 +2167,6 @@ ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer:: lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat `{` character ArenaVector specifiers(Allocator()->Adapter()); - binder::ModuleScope::ExportDeclList exportDecls(Allocator()->Adapter()); while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { @@ -2010,8 +2193,6 @@ ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer:: specifier->SetRange({local->Start(), exported->End()}); specifiers.push_back(specifier); - auto *decl = Binder()->AddDecl(startLoc, exported->Name(), local->Name(), specifier); - exportDecls.push_back(decl); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat comma @@ -2027,9 +2208,11 @@ ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer:: source = ParseFromClause(); } + // record ExportEntry + AddExportNamedEntryItem(specifiers, source); + auto *exportDeclaration = AllocNode(source, std::move(specifiers)); exportDeclaration->SetRange({startLoc, endPos}); - Binder()->GetScope()->AsModuleScope()->AddExportDecl(exportDeclaration, std::move(exportDecls)); ConsumeSemicolon(exportDeclaration); return exportDeclaration; @@ -2052,27 +2235,25 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); } - ExportDeclarationContext exportDeclCtx(Binder()); - switch (lexer_->GetToken().Type()) { case lexer::TokenType::KEYW_VAR: { - decl = ParseVariableDeclaration(VariableParsingFlags::VAR, isDeclare); + decl = ParseVariableDeclaration(VariableParsingFlags::VAR, isDeclare, true); break; } case lexer::TokenType::KEYW_CONST: { - decl = ParseVariableDeclaration(VariableParsingFlags::CONST, isDeclare); + decl = ParseVariableDeclaration(VariableParsingFlags::CONST, isDeclare, true); break; } case lexer::TokenType::KEYW_LET: { - decl = ParseVariableDeclaration(VariableParsingFlags::LET, isDeclare); + decl = ParseVariableDeclaration(VariableParsingFlags::LET, isDeclare, true); break; } case lexer::TokenType::KEYW_FUNCTION: { - decl = ParseFunctionDeclaration(false, ParserStatus::NO_OPTS, isDeclare); + decl = ParseFunctionDeclaration(false, ParserStatus::NO_OPTS, isDeclare, true); break; } case lexer::TokenType::KEYW_CLASS: { - decl = ParseClassDeclaration(true, std::move(decorators), isDeclare); + decl = ParseClassDeclaration(true, std::move(decorators), isDeclare, false, true); break; } case lexer::TokenType::LITERAL_IDENT: { @@ -2123,7 +2304,7 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: } lexer_->NextToken(); // eat `async` keyword - decl = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); + decl = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION, false, true); } } @@ -2131,13 +2312,13 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: ConsumeSemicolon(decl); } + AddExportLocalEntryItem(decl); + lexer::SourcePosition endLoc = decl->End(); ArenaVector specifiers(Allocator()->Adapter()); auto *exportDeclaration = AllocNode(decl, std::move(specifiers)); exportDeclaration->SetRange({startLoc, endLoc}); - exportDeclCtx.BindExportDecl(exportDeclaration); - return exportDeclaration; } @@ -2158,13 +2339,13 @@ ir::Statement *ParserImpl::ParseExportDeclaration(StatementParsingFlags flags, lexer_->NextToken(); // eat `export` keyword switch (lexer_->GetToken().Type()) { - case lexer::TokenType::KEYW_DEFAULT: { + case lexer::TokenType::KEYW_DEFAULT: { // export default Id return ParseExportDefaultDeclaration(startLoc, std::move(decorators)); } - case lexer::TokenType::PUNCTUATOR_MULTIPLY: { + case lexer::TokenType::PUNCTUATOR_MULTIPLY: { // export * ... return ParseExportAllDeclaration(startLoc); } - case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { + case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { // export { ... } ... return ParseExportNamedSpecifiers(startLoc); } case lexer::TokenType::KEYW_IMPORT: { @@ -2177,7 +2358,7 @@ ir::Statement *ParserImpl::ParseExportDeclaration(StatementParsingFlags flags, [[fallthrough]]; } - default: { + default: { // export [var] id ir::ExportNamedDeclaration *exportDecl = ParseNamedExportDeclaration(startLoc, std::move(decorators)); if (Extension() == ScriptExtension::TS && exportDecl->Decl()->IsVariableDeclaration() && @@ -2208,7 +2389,7 @@ void ParserImpl::ParseNameSpaceImport(ArenaVector *specifiers) specifier->SetRange({namespaceStart, lexer_->GetToken().End()}); specifiers->push_back(specifier); - Binder()->AddDecl(namespaceStart, "*", local->Name(), specifier); + Binder()->AddDecl(namespaceStart, local->Name(), binder::DeclModuleStatus::NONE); lexer_->NextToken(); // eat local name } @@ -2265,7 +2446,7 @@ void ParserImpl::ParseNamedImportSpecifiers(ArenaVector *specifie specifier->SetRange({imported->Start(), local->End()}); specifiers->push_back(specifier); - Binder()->AddDecl(imported->Start(), imported->Name(), local->Name(), specifier); + Binder()->AddDecl(local->Start(), local->Name(), binder::DeclModuleStatus::IMPORT); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat comma @@ -2334,9 +2515,9 @@ ir::AstNode *ParserImpl::ParseImportDefaultSpecifier(ArenaVector specifier->SetRange(specifier->Local()->Range()); specifiers->push_back(specifier); - Binder()->AddDecl(local->Start(), "default", local->Name(), specifier); + Binder()->AddDecl(local->Start(), local->Name(), binder::DeclModuleStatus::IMPORT); - lexer_->NextToken(); // eat specifier name + // lexer_->NextToken(); // eat specifier name if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(); // eat comma @@ -2373,6 +2554,7 @@ ir::AstNode *ParserImpl::ParseImportSpecifiers(ArenaVector *speci { ASSERT(specifiers->empty()); + // import [default] from 'source' if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { ir::AstNode *astNode = ParseImportDefaultSpecifier(specifiers); if (astNode != nullptr) { @@ -2390,8 +2572,6 @@ ir::AstNode *ParserImpl::ParseImportSpecifiers(ArenaVector *speci ir::Statement *ParserImpl::ParseImportDeclaration(StatementParsingFlags flags) { - ImportDeclarationContext importCtx(Binder()); - if (Extension() == ScriptExtension::JS) { if (!(flags & StatementParsingFlags::GLOBAL)) { ThrowSyntaxError("'import' and 'export' may only appear at the top level"); @@ -2403,6 +2583,7 @@ ir::Statement *ParserImpl::ParseImportDeclaration(StatementParsingFlags flags) } char32_t nextChar = lexer_->Lookahead(); + // dynamic import || import.meta if (nextChar == LEX_CHAR_LEFT_PAREN || nextChar == LEX_CHAR_DOT) { return ParseExpressionStatement(); } @@ -2423,14 +2604,16 @@ ir::Statement *ParserImpl::ParseImportDeclaration(StatementParsingFlags flags) return astNode->AsTSImportEqualsDeclaration(); } source = ParseFromClause(true); + AddImportEntryItem(source, &specifiers); } else { + // import 'source' source = ParseFromClause(false); + AddImportEntryItem(source, nullptr); } lexer::SourcePosition endLoc = source->End(); auto *importDeclaration = AllocNode(source, std::move(specifiers)); importDeclaration->SetRange({startLoc, endLoc}); - importCtx.BindImportDecl(importDeclaration); ConsumeSemicolon(importDeclaration); diff --git a/es2panda/util/helpers.cpp b/es2panda/util/helpers.cpp index 5d16303d8a..2d2db346c5 100644 --- a/es2panda/util/helpers.cpp +++ b/es2panda/util/helpers.cpp @@ -300,7 +300,7 @@ util::StringView Helpers::FunctionName(const ir::ScriptFunction *func) } if (func->Parent()->IsFunctionDeclaration()) { - return "*default*"; + return "default"; } const ir::AstNode *parent = func->Parent()->Parent(); @@ -361,6 +361,9 @@ util::StringView Helpers::FunctionName(const ir::ScriptFunction *func) break; } + case ir::AstNodeType::EXPORT_DEFAULT_DECLARATION: { + return util::StringView("default"); + } default: break; } diff --git a/test262/run_sunspider.py b/test262/run_sunspider.py index f2802d8e9c..806504521f 100755 --- a/test262/run_sunspider.py +++ b/test262/run_sunspider.py @@ -213,6 +213,15 @@ class ArkProgram(): self.arch_root = self.args.ark_arch_root + def gen_dependency_abc(self, dependency): + cmd_args = [] + output_file = os.path.splitext(os.path.join(BASE_OUT_DIR, os.path.split(dependency)[1]))[0] + output_abc = f"{output_file}.abc" + frontend_tool = ARK_FRONTEND_BINARY_LIST[1] + cmd_args = [frontend_tool, dependency, '--output', output_abc, '--module'] + proc = subprocess.Popen(cmd_args) + proc.wait() + def gen_abc(self): js_file = self.js_file file_name_pre = os.path.splitext(js_file)[0] @@ -222,6 +231,13 @@ class ArkProgram(): mod_opt_index = 0 cmd_args = [] frontend_tool = self.ark_frontend_binary + + # pre-generate the dependencies' abc when ark_frontend is [es2panda] + if file_name in self.module_list and self.ark_frontend == ARK_FRONTEND_LIST[1]: + dependencies = collect_module_dependencies(js_file, os.path.join(TEST_ES2021_DIR, "language/module-code"), []) + for dependency in list(set(dependencies)): + self.gen_dependency_abc(dependency) + if self.ark_frontend == ARK_FRONTEND_LIST[0]: mod_opt_index = 3 cmd_args = ['node', '--expose-gc', frontend_tool, diff --git a/test262/utils.py b/test262/utils.py index 3263aef7f4..17501580a8 100755 --- a/test262/utils.py +++ b/test262/utils.py @@ -25,6 +25,7 @@ import datetime import time import shutil import platform +import re TERM_NORMAL = '\033[0m' TERM_YELLOW = '\033[1;33m' @@ -157,3 +158,25 @@ def npm_install(cwd): cmd = ['npm', 'install'] ret = run_cmd_cwd(cmd, cwd) assert not ret, f"\n error: Failed to 'npm install'" + +def search_dependency(file, directory): + for root, dirs, files in os.walk(directory, topdown=True): + for f in files: + if f == file: + return os.path.join(root, f) + +def collect_module_dependencies(file, directory, traversedDependencies): + dependencies = [] + traversedDependencies.append(file) + with open(file, 'r') as f: + content = f.read() + result_arr = re.findall(r'(import|from)(?:\s*)(\'(\.\/.*)\'|"(\.\/.*)")', content) + for result in result_arr: + specifier = result[2] if len(result[2]) != 0 else result[3] + if re.search(r'\S+_FIXTURE.js$', specifier): + dependency = search_dependency(specifier.lstrip('./'), directory) + if dependency not in traversedDependencies: + dependencies.extend(collect_module_dependencies(dependency, directory, list(set(traversedDependencies)))) + dependencies.append(dependency) + + return dependencies \ No newline at end of file -- Gitee From 4c18db5323f785d97f9ea52a17bbd41218cb7a06 Mon Sep 17 00:00:00 2001 From: hufeng Date: Sun, 31 Jul 2022 21:58:01 +0800 Subject: [PATCH 2/4] Rework the implementation ISSUE: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I5JRWQ Signed-off-by: hufeng Change-Id: I176cd66c4e502b81e6a42b06f51f89434a2b9520 --- es2panda/BUILD.gn | 5 +- es2panda/binder/binder.cpp | 41 ++- es2panda/binder/binder.h | 20 +- es2panda/binder/declaration.h | 55 ++-- es2panda/binder/module.cpp | 239 ------------------ es2panda/binder/scope.cpp | 30 +-- es2panda/binder/scope.h | 53 ++-- es2panda/binder/variableFlags.h | 9 + es2panda/compiler/base/hoisting.cpp | 32 ++- es2panda/compiler/core/compileQueue.cpp | 63 +++-- es2panda/compiler/core/compileQueue.h | 48 +++- es2panda/compiler/core/compilerContext.cpp | 2 +- es2panda/compiler/core/compilerImpl.cpp | 2 +- .../compiler/core/{ => emitter}/emitter.cpp | 175 ++----------- .../compiler/core/{ => emitter}/emitter.h | 52 ++-- .../core/emitter/moduleRecordEmitter.cpp | 140 ++++++++++ es2panda/compiler/core/pandagen.cpp | 9 +- es2panda/compiler/core/pandagen.h | 8 - es2panda/compiler/core/regScope.cpp | 1 - .../ir/module/exportDefaultDeclaration.cpp | 2 +- es2panda/ir/statements/classDeclaration.cpp | 2 +- es2panda/parser/context/parserContext.h | 2 +- es2panda/parser/module/module.cpp | 164 ++++++++++++ es2panda/{binder => parser/module}/module.h | 160 +++++------- es2panda/parser/parserFlags.h | 1 + es2panda/parser/parserImpl.cpp | 17 +- es2panda/parser/parserImpl.h | 27 +- es2panda/parser/program/program.cpp | 4 + es2panda/parser/program/program.h | 7 + es2panda/parser/statementParser.cpp | 218 ++++++++-------- es2panda/util/helpers.cpp | 5 +- 31 files changed, 796 insertions(+), 797 deletions(-) delete mode 100644 es2panda/binder/module.cpp rename es2panda/compiler/core/{ => emitter}/emitter.cpp (63%) rename es2panda/compiler/core/{ => emitter}/emitter.h (70%) create mode 100644 es2panda/compiler/core/emitter/moduleRecordEmitter.cpp create mode 100644 es2panda/parser/module/module.cpp rename es2panda/{binder => parser/module}/module.h (36%) diff --git a/es2panda/BUILD.gn b/es2panda/BUILD.gn index a44cbe3429..38e1f79d15 100644 --- a/es2panda/BUILD.gn +++ b/es2panda/BUILD.gn @@ -19,7 +19,6 @@ es2panda_src = [ "es2panda.cpp", "binder/binder.cpp", "binder/declaration.cpp", - "binder/module.cpp", "binder/scope.cpp", "binder/variable.cpp", "compiler/base/catchTable.cpp", @@ -34,7 +33,8 @@ es2panda_src = [ "compiler/core/compilerContext.cpp", "compiler/core/compilerImpl.cpp", "compiler/core/dynamicContext.cpp", - "compiler/core/emitter.cpp", + "compiler/core/emitter/emitter.cpp", + "compiler/core/emitter/moduleRecordEmitter.cpp", "compiler/core/envScope.cpp", "compiler/core/function.cpp", "compiler/core/inlineCache.cpp", @@ -186,6 +186,7 @@ es2panda_src = [ "lexer/token/token.cpp", "parser/context/parserContext.cpp", "parser/expressionParser.cpp", + "parser/module/module.cpp", "parser/parserImpl.cpp", "parser/program/program.cpp", "parser/statementParser.cpp", diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index aa97f5e4b7..909a4f54d3 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -30,7 +30,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -76,6 +77,16 @@ void Binder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::St throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col); } +void Binder::ThrowUndeclaredExport(const lexer::SourcePosition &pos, const util::StringView &name) +{ + lexer::LineIndex index(program_->SourceCode()); + lexer::SourceLocation loc = index.GetLocation(pos); + + std::stringstream ss; + ss << "Export name '" << name << "' is not defined."; + throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col); +} + void Binder::IdentifierAnalysis() { ASSERT(program_->Ast()); @@ -86,6 +97,22 @@ void Binder::IdentifierAnalysis() AddMandatoryParams(); } +void Binder::ValidateLocalExportDeclared(const ir::ExportNamedDeclaration *exportDecl) +{ + if (exportDecl->Source() != nullptr || exportDecl->Decl() != nullptr) { + return; + } + + ASSERT(topScope_->IsModuleScope()); + for (auto *it : exportDecl->Specifiers()) { + auto localName = it->AsExportSpecifier()->Local()->Name(); + if (topScope_->FindLocal(localName) == nullptr) { + ThrowUndeclaredExport(it->AsExportSpecifier()->Local()->Start(), localName); + } + topScope_->AsModuleScope()->SetVariableAsExported(Allocator(), localName); + } +} + void Binder::LookupReference(const util::StringView &name) { ScopeFindResult res = scope_->Find(name); @@ -152,7 +179,9 @@ void Binder::LookupIdentReference(ir::Identifier *ident) return; } - if (res.variable->Declaration()->IsLetOrConstOrClassDecl() && !res.variable->HasFlag(VariableFlags::INITIALIZED)) { + auto decl = res.variable->Declaration(); + if (decl->IsLetOrConstOrClassDecl() && !decl->HasFlag(DeclarationFlags::NAMESPACE_IMPORT) && + !res.variable->HasFlag(VariableFlags::INITIALIZED)) { ident->SetTdz(); } @@ -258,7 +287,7 @@ void Binder::BuildClassDefinition(ir::ClassDefinition *classDef) className = classDef->Ident()->Name(); } else { ASSERT(scope_->IsModuleScope()); - className = util::StringView("*default*"); + className = parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; } ScopeFindResult res = scope_->Find(className); @@ -447,6 +476,12 @@ void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) BuildCatchClause(childNode->AsCatchClause()); break; } + case ir::AstNodeType::EXPORT_NAMED_DECLARATION: { + ValidateLocalExportDeclared(childNode->AsExportNamedDeclaration()); + + ResolveReferences(childNode); + break; + } default: { ResolveReferences(childNode); break; diff --git a/es2panda/binder/binder.h b/es2panda/binder/binder.h index ac24e9a86e..b0deb4fb0c 100644 --- a/es2panda/binder/binder.h +++ b/es2panda/binder/binder.h @@ -28,9 +28,9 @@ class BlockStatement; class CatchClause; class ClassDefinition; class Expression; +class ExportNamedDeclaration; class ForUpdateStatement; class Identifier; -class ImportNamespaceSpecifier; class ScriptFunction; class Statement; class VariableDeclarator; @@ -58,6 +58,9 @@ public: template T *AddDecl(const lexer::SourcePosition &pos, Args &&... args); + template + T *AddDecl(const lexer::SourcePosition &pos, DeclarationFlags flag, Args &&... args); + template T *AddTsDecl(const lexer::SourcePosition &pos, Args &&... args); @@ -74,6 +77,7 @@ public: } [[noreturn]] void ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name); + [[noreturn]] void ThrowUndeclaredExport(const lexer::SourcePosition &pos, const util::StringView &name); template friend class LexicalScope; @@ -142,6 +146,7 @@ private: void LookupIdentReference(ir::Identifier *ident); void ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode); void ResolveReferences(const ir::AstNode *parent); + void ValidateLocalExportDeclared(const ir::ExportNamedDeclaration *exportDecl); parser::Program *program_ {}; FunctionScope *topScope_ {}; @@ -216,6 +221,19 @@ T *Binder::AddDecl(const lexer::SourcePosition &pos, Args &&... args) ThrowRedeclaration(pos, decl->Name()); } + +template +T *Binder::AddDecl(const lexer::SourcePosition &pos, DeclarationFlags flag, Args &&... args) +{ + T *decl = Allocator()->New(std::forward(args)...); + decl->AddFlag(flag); + + if (scope_->AddDecl(Allocator(), decl, program_->Extension())) { + return decl; + } + + ThrowRedeclaration(pos, decl->Name()); +} } // namespace panda::es2panda::binder #endif diff --git a/es2panda/binder/declaration.h b/es2panda/binder/declaration.h index e143c63db4..ec2da81fd2 100644 --- a/es2panda/binder/declaration.h +++ b/es2panda/binder/declaration.h @@ -32,12 +32,6 @@ namespace panda::es2panda::binder { class Scope; class LocalScope; -enum class DeclModuleStatus { - NONE = 0, - IMPORT, - EXPORT, -}; - #define DECLARE_CLASSES(decl_kind, className) class className; DECLARATION_KINDS(DECLARE_CLASSES) #undef DECLARE_CLASSES @@ -88,44 +82,34 @@ public: return IsLetDecl() || IsConstDecl() || IsClassDecl(); } - void SetModuleStatus(DeclModuleStatus status) - { - moduleStatus_ = status; - } - - bool IsExportedDecl() const + void AddFlag(DeclarationFlags flag) { - return moduleStatus_ == DeclModuleStatus::EXPORT; + flags_ |= flag; } - bool IsImportedDecl() const + bool HasFlag(DeclarationFlags flag) const { - return moduleStatus_ == DeclModuleStatus::IMPORT; + return (flags_ & flag) != 0; } - bool IsNoneModuleDecl() const + bool IsImportOrExportDecl() const { - return moduleStatus_ == DeclModuleStatus::NONE; + return HasFlag(DeclarationFlags::IMPORT | DeclarationFlags::EXPORT); } protected: - explicit Decl(util::StringView name, DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) - : name_(name), moduleStatus_(moduleStatus) - { - } + explicit Decl(util::StringView name) : name_(name) {} util::StringView name_; - DeclModuleStatus moduleStatus_; + DeclarationFlags flags_ {}; const ir::AstNode *node_ {}; }; template class MultiDecl : public Decl { public: - explicit MultiDecl(ArenaAllocator *allocator, - util::StringView name, - DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) - : Decl(name, moduleStatus), declarations_(allocator->Adapter()) + explicit MultiDecl(ArenaAllocator *allocator, util::StringView name) + : Decl(name), declarations_(allocator->Adapter()) { } @@ -184,11 +168,8 @@ public: class FunctionDecl : public MultiDecl { public: - explicit FunctionDecl(ArenaAllocator *allocator, - util::StringView name, - const ir::AstNode *node, - DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) - : MultiDecl(allocator, name, moduleStatus) + explicit FunctionDecl(ArenaAllocator *allocator, util::StringView name, const ir::AstNode *node) + : MultiDecl(allocator, name) { node_ = node; } @@ -241,8 +222,7 @@ public: class VarDecl : public Decl { public: - explicit VarDecl(util::StringView name, DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) - : Decl(name, moduleStatus) {} + explicit VarDecl(util::StringView name) : Decl(name) {} DeclType Type() const override { @@ -252,8 +232,7 @@ public: class LetDecl : public Decl { public: - explicit LetDecl(util::StringView name, DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) - : Decl(name, moduleStatus) {} + explicit LetDecl(util::StringView name) : Decl(name) {} DeclType Type() const override { @@ -263,8 +242,7 @@ public: class ConstDecl : public Decl { public: - explicit ConstDecl(util::StringView name, DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) - : Decl(name, moduleStatus) {} + explicit ConstDecl(util::StringView name) : Decl(name) {} DeclType Type() const override { @@ -274,8 +252,7 @@ public: class ClassDecl : public Decl { public: - explicit ClassDecl(util::StringView name, DeclModuleStatus moduleStatus = DeclModuleStatus::NONE) - : Decl(name, moduleStatus) {} + explicit ClassDecl(util::StringView name) : Decl(name) {} DeclType Type() const override { diff --git a/es2panda/binder/module.cpp b/es2panda/binder/module.cpp deleted file mode 100644 index 553edeb8fc..0000000000 --- a/es2panda/binder/module.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/** - * Copyright (c) 2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "module.h" - -#include - -namespace panda::es2panda::binder { - - int SourceTextModuleRecord::AddModuleRequest(const util::StringView source, lexer::SourcePosition sourcePos) - { - ASSERT(!source.Empty()); - int moduleRequestsSize = static_cast(moduleRequestsMap_.size()); - if (moduleRequestsMap_.find(source) == moduleRequestsMap_.end()) { - moduleRequests_.emplace_back(source); - } - auto insertedRes = moduleRequestsMap_.insert( - std::make_pair(source, ModuleRequest(moduleRequestsSize, sourcePos.index)) - ); - return insertedRes.first->second.idx; - } - - void SourceTextModuleRecord::AddImportEntry(const util::StringView importName, - const util::StringView localName, - const util::StringView moduleRequest, - const lexer::SourcePosition pos, - const lexer::SourcePosition sourcePos) - { - auto *importEntry = allocator_->New(pos); - importEntry->importName = importName; - importEntry->localName = localName; - importEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); - ASSERT(!importEntry->importName.Empty()); - ASSERT(!importEntry->localName.Empty()); - ASSERT(importEntry->exportName.Empty()); - ASSERT(importEntry->moduleRequest != -1); - regularImportEntries_.insert(std::make_pair(importEntry->localName, importEntry)); - } - - void SourceTextModuleRecord::AddEmptyImportEntry(const util::StringView moduleRequest, - const lexer::SourcePosition sourcePos) - { - AddModuleRequest(moduleRequest, sourcePos); - } - - void SourceTextModuleRecord::AddStarImportEntry(const ir::AstNode *moduleNode, - const util::StringView localName, - const util::StringView moduleRequest, - const lexer::SourcePosition pos, - const lexer::SourcePosition sourcePos) - { - auto *starImportEntry = allocator_->New(pos); - starImportEntry->moduleNode = moduleNode; - starImportEntry->localName = localName; - starImportEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); - ASSERT(starImportEntry->moduleNode != nullptr); - ASSERT(starImportEntry->importName.Empty()); - ASSERT(!starImportEntry->localName.Empty()); - ASSERT(starImportEntry->exportName.Empty()); - ASSERT(starImportEntry->moduleRequest != -1); - namespaceImportEntries_.push_back(starImportEntry); - } - - void SourceTextModuleRecord::AddLocalExportEntry(const util::StringView exportName, - const util::StringView localName, - const lexer::SourcePosition pos) - { - auto *localExportEntry = allocator_->New(pos); - localExportEntry->exportName = exportName; - localExportEntry->localName = localName; - ASSERT(localExportEntry->importName.Empty()); - ASSERT(!localExportEntry->localName.Empty()); - ASSERT(!localExportEntry->exportName.Empty()); - ASSERT(localExportEntry->moduleRequest == -1); - localExportEntries_.insert(std::make_pair(localExportEntry->localName, localExportEntry)); - } - - void SourceTextModuleRecord::AddIndirectExportEntry(const util::StringView importName, - const util::StringView exportName, - const util::StringView moduleRequest, - const lexer::SourcePosition pos, - const lexer::SourcePosition sourcePos) - { - auto *indirectExportEntry = allocator_->New(pos); - indirectExportEntry->importName = importName; - indirectExportEntry->exportName = exportName; - indirectExportEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); - ASSERT(!indirectExportEntry->importName.Empty()); - ASSERT(indirectExportEntry->localName.Empty()); - ASSERT(!indirectExportEntry->exportName.Empty()); - ASSERT(indirectExportEntry->moduleRequest != -1); - indirectExportEntries_.push_back(indirectExportEntry); - } - - void SourceTextModuleRecord::AddStarExportEntry(const util::StringView moduleRequest, - const lexer::SourcePosition pos, - const lexer::SourcePosition sourcePos) - { - auto *starExportEntry = allocator_->New(pos); - starExportEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); - ASSERT(starExportEntry->importName.Empty()); - ASSERT(starExportEntry->localName.Empty()); - ASSERT(starExportEntry->exportName.Empty()); - ASSERT(starExportEntry->moduleRequest != -1); - starExportEntries_.push_back(starExportEntry); - } - - const SourceTextModuleRecord::Entry *SourceTextModuleRecord::NextDuplicateExportEntry( - const Entry *entry, - const Entry *duplicate, - ArenaMap &exportNameEntries) - { - ASSERT(!entry->exportName.Empty()); - auto insertRes = exportNameEntries.insert(std::make_pair(entry->exportName, entry)); - - // successfully inserted when there has no duplicate entry - if (insertRes.second) { - return duplicate; - } - - // find [entry] has same export name with one of the exportNameEntries - if (duplicate == nullptr) { - // update duplicate entry if pre duplicate is null - duplicate = insertRes.first->second; - } - - // return the entry at the backward position - if (entry->position.index > duplicate->position.index) { - return entry; - } - - return duplicate; - } - - const SourceTextModuleRecord::Entry *SourceTextModuleRecord::SearchDupExport() - { - const SourceTextModuleRecord::Entry *duplicateEntry = nullptr; - ArenaMap exportNameEntries( - allocator_->Adapter()); - - for (auto const &entryUnit : localExportEntries_) { - duplicateEntry = NextDuplicateExportEntry(entryUnit.second, duplicateEntry, exportNameEntries); - } - - for (auto entry : indirectExportEntries_) { - duplicateEntry = NextDuplicateExportEntry(entry, duplicateEntry, exportNameEntries); - } - - return duplicateEntry; - } - - bool SourceTextModuleRecord::ValidateModuleRecordEntries(ModuleScope *moduleScope, - std::string &errorMessage, - lexer::SourcePosition &errorPos) - { - ASSERT(this == moduleScope->GetModuleRecord()); - const SourceTextModuleRecord::Entry *dupExportEntry = SearchDupExport(); - if (dupExportEntry != nullptr) { - errorMessage.append("Duplicate export name of '" + dupExportEntry->exportName.Mutf8() + "'"); - errorPos.index = dupExportEntry->position.index; - errorPos.line = dupExportEntry->position.line; - return false; - } - - for (const auto &entryUnit : localExportEntries_) { - const SourceTextModuleRecord::Entry *e = entryUnit.second; - ASSERT(!e->exportName.Empty()); - if (moduleScope->FindLocal(e->localName) == nullptr && !e->localName.Is("*default*")) { - errorMessage.append("Export name '" + e->localName.Mutf8() + "' is not defined"); - errorPos.index = e->position.index; - errorPos.line = e->position.line; - return false; - } - } - - /* - * Translate implicit indirectExport entry into explicit entry - * e.g. import { x } from 'test.js'; export { x } - * ---> - * import { x } from 'test.js'; export { x } from 'test.js'; - */ - for (auto it = localExportEntries_.begin(); it != localExportEntries_.end();) { - auto exportEntry = it->second; - ASSERT(!exportEntry->localName.Empty()); - auto importEntry = regularImportEntries_.find(exportEntry->localName); - if (importEntry != regularImportEntries_.end()) { - ASSERT(exportEntry->importName.Empty()); - ASSERT(exportEntry->moduleRequest == -1); - ASSERT(!importEntry->second->importName.Empty()); - ASSERT(importEntry->second->moduleRequest != -1); - exportEntry->importName = importEntry->second->importName; - exportEntry->moduleRequest = importEntry->second->moduleRequest; - exportEntry->localName = util::StringView(""); - exportEntry->position = importEntry->second->position; - indirectExportEntries_.push_back(exportEntry); - it = localExportEntries_.erase(it); - continue; - } - ++it; - } - return true; - } - - void SourceTextModuleRecord::SetLocalExportEntriesVariables(ModuleScope *moduleScope) - { - for (auto it = localExportEntries_.begin(); - it != localExportEntries_.end(); - it = localExportEntries_.upper_bound(it->first)) { - moduleScope->SetVariableAsExported(allocator_, it->first); - } - } - - void SourceTextModuleRecord::SetNameSpaceImportInitialized(ModuleScope *moduleScope) - { - for (auto namespaceEntry : namespaceImportEntries_) { - auto *var = moduleScope->FindLocal(namespaceEntry->localName); - ASSERT(var != nullptr); - var->AddFlag(VariableFlags::INITIALIZED); - } - } - - void SourceTextModuleRecord::SetModuleEnvironment(ModuleScope *moduleScope) - { - SetNameSpaceImportInitialized(moduleScope); - SetLocalExportEntriesVariables(moduleScope); - } -} // namespace panda::es2panda::binder \ No newline at end of file diff --git a/es2panda/binder/scope.cpp b/es2panda/binder/scope.cpp index 012100516a..391630c70c 100644 --- a/es2panda/binder/scope.cpp +++ b/es2panda/binder/scope.cpp @@ -348,14 +348,12 @@ void ModuleScope::SetVariableAsExported(ArenaAllocator *allocator, util::StringV // Since the module's exported [localName] has been validated before, // [localName] must have a binding now. ASSERT(res != bindings_.end()); - auto *decl = res->second->Declaration(); - decl->SetModuleStatus(DeclModuleStatus::EXPORT); - VariableFlags flags = res->second->Flags(); - if ((flags & VariableFlags::IMPORT) == 0) { - // re-exported importedName should not be LOCAL_EXPORT - flags |= VariableFlags::LOCAL_EXPORT; + if (!res->second->IsModuleVariable()) { + auto *decl = res->second->Declaration(); + decl->AddFlag(DeclarationFlags::EXPORT); + VariableFlags flags = res->second->Flags(); + res->second = allocator->New(decl, flags | VariableFlags::LOCAL_EXPORT); } - res->second = allocator->New(decl, flags); } bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, @@ -369,17 +367,17 @@ bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl if (shadowed) { return false; } - return newDecl->IsNoneModuleDecl() ? - AddVar(allocator, currentVariable, newDecl) : - AddVar(allocator, currentVariable, newDecl); + return newDecl->IsImportOrExportDecl() ? + AddVar(allocator, currentVariable, newDecl) : + AddVar(allocator, currentVariable, newDecl); } case DeclType::FUNC: { if (currentVariable) { return false; } - return newDecl->IsNoneModuleDecl() ? - AddFunction(allocator, currentVariable, newDecl, extension) : - AddFunction(allocator, currentVariable, newDecl, extension); + return newDecl->IsImportOrExportDecl() ? + AddFunction(allocator, currentVariable, newDecl, extension) : + AddFunction(allocator, currentVariable, newDecl, extension); } case DeclType::ENUM: { bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}); @@ -395,9 +393,9 @@ bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl if (currentVariable) { return false; } - return newDecl->IsNoneModuleDecl() ? - AddLexical(allocator, currentVariable, newDecl) : - AddLexical(allocator, currentVariable, newDecl); + return newDecl->IsImportOrExportDecl() ? + AddLexical(allocator, currentVariable, newDecl) : + AddLexical(allocator, currentVariable, newDecl); } } } diff --git a/es2panda/binder/scope.h b/es2panda/binder/scope.h index dc5a46028a..bd038ca9f2 100644 --- a/es2panda/binder/scope.h +++ b/es2panda/binder/scope.h @@ -17,7 +17,6 @@ #define ES2PANDA_COMPILER_SCOPES_SCOPE_H #include -#include #include #include #include @@ -574,8 +573,7 @@ class GlobalScope : public FunctionScope { public: explicit GlobalScope(ArenaAllocator *allocator) : FunctionScope(allocator, nullptr) { - auto *paramScope = allocator->New(allocator, this); - paramScope_ = paramScope; + paramScope_ = allocator->New(allocator, this); } ScopeType Type() const override @@ -589,17 +587,9 @@ public: class ModuleScope : public FunctionScope { public: - explicit ModuleScope(ArenaAllocator *allocator) - : FunctionScope(allocator, nullptr), - moduleRecord_(new SourceTextModuleRecord(allocator)) - { - auto *paramScope = allocator->New(allocator, this); - paramScope_ = paramScope; - } - - ~ModuleScope() + explicit ModuleScope(ArenaAllocator *allocator) : FunctionScope(allocator, nullptr) { - delete moduleRecord_; + paramScope_ = allocator->New(allocator, this); } ScopeType Type() const override @@ -607,26 +597,22 @@ public: return ScopeType::MODULE; } - SourceTextModuleRecord *GetModuleRecord() const - { - return moduleRecord_; - } - void SetVariableAsExported(ArenaAllocator *allocator, util::StringView localName); bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension) override; - -private: - SourceTextModuleRecord *moduleRecord_; }; template bool VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { - VariableFlags flags = newDecl->IsNoneModuleDecl() ? VariableFlags::HOIST_VAR : - newDecl->IsImportedDecl() ? VariableFlags::HOIST_VAR | VariableFlags::IMPORT : - VariableFlags::HOIST_VAR | VariableFlags::LOCAL_EXPORT; + VariableFlags flags = VariableFlags::HOIST_VAR; + if (newDecl->HasFlag(DeclarationFlags::EXPORT)) { + flags |= VariableFlags::LOCAL_EXPORT; + } else if (newDecl->HasFlag(DeclarationFlags::IMPORT)) { + flags |= VariableFlags::IMPORT; + } + if (!currentVariable) { bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); return true; @@ -654,10 +640,11 @@ bool VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVari [[maybe_unused]] ScriptExtension extension) { VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST; - - flags = newDecl->IsNoneModuleDecl() ? flags : - newDecl->IsImportedDecl() ? flags | VariableFlags::IMPORT : - flags | VariableFlags::LOCAL_EXPORT; + if (newDecl->HasFlag(DeclarationFlags::EXPORT)) { + flags |= VariableFlags::LOCAL_EXPORT; + } else if (newDecl->HasFlag(DeclarationFlags::IMPORT)) { + flags |= VariableFlags::IMPORT; + } if (!currentVariable) { bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); @@ -694,9 +681,13 @@ bool VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Var template bool VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { - VariableFlags flags = newDecl->IsNoneModuleDecl() ? VariableFlags::NONE : - newDecl->IsImportedDecl() ? VariableFlags::NONE | VariableFlags::IMPORT : - VariableFlags::NONE | VariableFlags::LOCAL_EXPORT; + VariableFlags flags = VariableFlags::NONE; + if (newDecl->HasFlag(DeclarationFlags::EXPORT)) { + flags |= VariableFlags::LOCAL_EXPORT; + } else if (newDecl->HasFlag(DeclarationFlags::IMPORT)) { + flags |= VariableFlags::IMPORT; + } + if (currentVariable) { return false; } diff --git a/es2panda/binder/variableFlags.h b/es2panda/binder/variableFlags.h index d262475ba4..2127e3eade 100644 --- a/es2panda/binder/variableFlags.h +++ b/es2panda/binder/variableFlags.h @@ -137,6 +137,15 @@ enum class VariableScopeFlags { DEFINE_BITOPS(VariableScopeFlags) +enum class DeclarationFlags { + NONE = 0, + IMPORT = 1 << 0, + EXPORT = 1 << 1, + NAMESPACE_IMPORT = 1 << 2, +}; + +DEFINE_BITOPS(DeclarationFlags) + } // namespace panda::es2panda::binder #endif diff --git a/es2panda/compiler/base/hoisting.cpp b/es2panda/compiler/base/hoisting.cpp index c5c143a05f..1ec33b1323 100644 --- a/es2panda/compiler/base/hoisting.cpp +++ b/es2panda/compiler/base/hoisting.cpp @@ -16,8 +16,10 @@ #include "hoisting.h" #include +#include #include #include +#include namespace panda::es2panda::compiler { @@ -39,11 +41,11 @@ static void HoistVar(PandaGen *pg, binder::Variable *var, const binder::VarDecl binder::ScopeFindResult result(decl->Name(), scope, 0, var); pg->LoadConst(decl->Node(), Constant::JS_UNDEFINED); - if (decl->IsNoneModuleDecl()) { - pg->StoreAccToLexEnv(decl->Node(), result, true); - } else { + if (decl->HasFlag(binder::DeclarationFlags::EXPORT)) { ASSERT(scope->IsModuleScope()); pg->StoreModuleVariable(decl->Node(), decl->Name()); + } else { + pg->StoreAccToLexEnv(decl->Node(), result, true); } } @@ -64,11 +66,27 @@ static void HoistFunction(PandaGen *pg, binder::Variable *var, const binder::Fun binder::ScopeFindResult result(decl->Name(), scope, 0, var); pg->DefineFunction(decl->Node(), scriptFunction, internalName); - if (decl->IsNoneModuleDecl()) { - pg->StoreAccToLexEnv(decl->Node(), result, true); - } else { + if (decl->HasFlag(binder::DeclarationFlags::EXPORT)) { ASSERT(scope->IsModuleScope()); pg->StoreModuleVariable(decl->Node(), decl->Name()); + } else { + pg->StoreAccToLexEnv(decl->Node(), result, true); + } +} + +static void HoistNameSpaceImports(PandaGen *pg) +{ + if (pg->Scope()->IsModuleScope()) { + parser::SourceTextModuleRecord *moduleRecord = pg->Binder()->Program()->ModuleRecord(); + ASSERT(moduleRecord != nullptr); + for (auto nameSpaceEntry : moduleRecord->GetNamespaceImportEntries()) { + auto *var = pg->TopScope()->FindLocal(nameSpaceEntry->localName_); + ASSERT(var != nullptr); + auto *node = var->Declaration()->Node(); + ASSERT(node != nullptr); + pg->GetModuleNamespace(node, nameSpaceEntry->localName_); + pg->StoreVar(node, {nameSpaceEntry->localName_, pg->TopScope(), 0, var}, true); + } } } @@ -91,6 +109,8 @@ void Hoisting::Hoist(PandaGen *pg) HoistFunction(pg, var, decl->AsFunctionDecl()); } } + + HoistNameSpaceImports(pg); } } // namespace panda::es2panda::compiler diff --git a/es2panda/compiler/core/compileQueue.cpp b/es2panda/compiler/core/compileQueue.cpp index dc826a43f3..3bc6866a0e 100644 --- a/es2panda/compiler/core/compileQueue.cpp +++ b/es2panda/compiler/core/compileQueue.cpp @@ -18,13 +18,29 @@ #include #include #include -#include +#include #include #include namespace panda::es2panda::compiler { -void CompileJob::Run() +void CompileJob::DependsOn(CompileJob *job) +{ + job->dependant_ = this; + dependencies_++; +} + +void CompileJob::Signal() +{ + { + std::lock_guard lock(m_); + dependencies_--; + } + + cond_.notify_one(); +} + +void CompileFunctionJob::Run() { std::unique_lock lock(m_); cond_.wait(lock, [this] { return dependencies_ == 0; }); @@ -37,31 +53,26 @@ void CompileJob::Run() FunctionEmitter funcEmitter(&allocator, &pg); funcEmitter.Generate(); - auto *emitter = context_->GetEmitter(); - emitter->AddFunction(&funcEmitter); - if (scope_->IsModuleScope()) { - emitter->AddSourceTextModuleRecord(&pg); - } + context_->GetEmitter()->AddFunction(&funcEmitter); if (dependant_) { dependant_->Signal(); } } -void CompileJob::DependsOn(CompileJob *job) +void CompileModuleRecordJob::Run() { - job->dependant_ = this; - dependencies_++; -} + std::unique_lock lock(m_); + cond_.wait(lock, [this] { return dependencies_ == 0; }); -void CompileJob::Signal() -{ - { - std::lock_guard lock(m_); - dependencies_--; - } + ModuleRecordEmitter moduleEmitter(context_->Binder()->Program()->ModuleRecord(), context_->NewLiteralIndex()); + moduleEmitter.Generate(); - cond_.notify_one(); + context_->GetEmitter()->AddSourceTextModuleRecord(&moduleEmitter, context_); + + if (dependant_) { + dependant_->Signal(); + } } CompileQueue::CompileQueue(size_t threadCount) @@ -92,10 +103,18 @@ void CompileQueue::Schedule(CompilerContext *context) ASSERT(jobsCount_ == 0); std::unique_lock lock(m_); const auto &functions = context->Binder()->Functions(); - jobs_ = new CompileJob[functions.size()](); for (auto *function : functions) { - jobs_[jobsCount_++].SetConext(context, function); + auto *funcJob = new CompileFunctionJob(context); + funcJob->SetFunctionScope(function); + jobs_.push_back(funcJob); + jobsCount_++; + } + + if (context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE) { + auto *moduleRecordJob = new CompileModuleRecordJob(context); + jobs_.push_back(moduleRecordJob); + jobsCount_++; } lock.unlock(); @@ -126,7 +145,7 @@ void CompileQueue::Consume() while (jobsCount_ > 0) { --jobsCount_; - auto &job = jobs_[jobsCount_]; + auto &job = *(jobs_[jobsCount_]); lock.unlock(); @@ -148,7 +167,7 @@ void CompileQueue::Wait() { std::unique_lock lock(m_); jobsFinished_.wait(lock, [this]() { return activeWorkers_ == 0 && jobsCount_ == 0; }); - delete[] jobs_; + jobs_.clear(); if (!errors_.empty()) { // NOLINTNEXTLINE diff --git a/es2panda/compiler/core/compileQueue.h b/es2panda/compiler/core/compileQueue.h index 5e227475ba..f53b8b4c6b 100644 --- a/es2panda/compiler/core/compileQueue.h +++ b/es2panda/compiler/core/compileQueue.h @@ -33,33 +33,53 @@ class CompilerContext; class CompileJob { public: - CompileJob() = default; + explicit CompileJob(CompilerContext *context) : context_(context) {}; NO_COPY_SEMANTIC(CompileJob); NO_MOVE_SEMANTIC(CompileJob); - ~CompileJob() = default; + virtual ~CompileJob() = default; + + virtual void Run() = 0; + void DependsOn(CompileJob *job); + void Signal(); + +protected: + [[maybe_unused]] CompilerContext *context_ {}; + std::mutex m_; + std::condition_variable cond_; + CompileJob *dependant_ {}; + size_t dependencies_ {0}; +}; + +class CompileFunctionJob : public CompileJob { +public: + explicit CompileFunctionJob(CompilerContext *context) : CompileJob(context) {}; + NO_COPY_SEMANTIC(CompileFunctionJob); + NO_MOVE_SEMANTIC(CompileFunctionJob); + ~CompileFunctionJob() = default; binder::FunctionScope *Scope() const { return scope_; } - void SetConext(CompilerContext *context, binder::FunctionScope *scope) + void SetFunctionScope(binder::FunctionScope *scope) { - context_ = context; scope_ = scope; } - void Run(); - void DependsOn(CompileJob *job); - void Signal(); - + void Run() override; private: - std::mutex m_; - std::condition_variable cond_; - CompilerContext *context_ {}; binder::FunctionScope *scope_ {}; - CompileJob *dependant_ {}; - size_t dependencies_ {0}; +}; + +class CompileModuleRecordJob : public CompileJob { +public: + explicit CompileModuleRecordJob(CompilerContext *context) : CompileJob(context) {}; + NO_COPY_SEMANTIC(CompileModuleRecordJob); + NO_MOVE_SEMANTIC(CompileModuleRecordJob); + ~CompileModuleRecordJob() = default; + + void Run() override; }; class CompileQueue { @@ -81,7 +101,7 @@ private: std::mutex m_; std::condition_variable jobsAvailable_; std::condition_variable jobsFinished_; - CompileJob *jobs_ {}; + std::vector jobs_ {}; size_t jobsCount_ {0}; size_t activeWorkers_ {0}; bool terminate_ {false}; diff --git a/es2panda/compiler/core/compilerContext.cpp b/es2panda/compiler/core/compilerContext.cpp index 6a97c410fd..0cb6270324 100644 --- a/es2panda/compiler/core/compilerContext.cpp +++ b/es2panda/compiler/core/compilerContext.cpp @@ -15,7 +15,7 @@ #include "compilerContext.h" -#include +#include namespace panda::es2panda::compiler { diff --git a/es2panda/compiler/core/compilerImpl.cpp b/es2panda/compiler/core/compilerImpl.cpp index c4ff569b2a..d459904a4e 100644 --- a/es2panda/compiler/core/compilerImpl.cpp +++ b/es2panda/compiler/core/compilerImpl.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include diff --git a/es2panda/compiler/core/emitter.cpp b/es2panda/compiler/core/emitter/emitter.cpp similarity index 63% rename from es2panda/compiler/core/emitter.cpp rename to es2panda/compiler/core/emitter/emitter.cpp index 654daae8f7..1045d77aec 100644 --- a/es2panda/compiler/core/emitter.cpp +++ b/es2panda/compiler/core/emitter/emitter.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -65,7 +64,6 @@ void FunctionEmitter::Generate() GenFunctionCatchTables(); GenFunctionICSize(); GenLiteralBuffers(); - GenSourceTextModuleRecord(); } const ArenaSet &FunctionEmitter::Strings() const @@ -293,134 +291,6 @@ void FunctionEmitter::GenLiteralBuffers() } } -void FunctionEmitter::GenModuleRequests(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray) -{ - auto &moduleRequests = moduleRecord->GetModuleRequests(); - panda::pandasm::LiteralArray::Literal moduleSize = { - .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(moduleRequests.size())}; - moduleLiteralArray.emplace_back(moduleSize); - for (auto request : moduleRequests) { - panda::pandasm::LiteralArray::Literal moduleRequest = { - .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = request.Mutf8()}; - moduleLiteralArray.emplace_back(moduleRequest); - } -} - -void FunctionEmitter::GenRegularImportEntries(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray) -{ - auto ®ularImportEntries = moduleRecord->GetRegularImportEntries(); - panda::pandasm::LiteralArray::Literal entrySize = { - .tag_ = panda::panda_file::LiteralTag::INTEGER, - .value_ = static_cast(regularImportEntries.size())}; - moduleLiteralArray.emplace_back(entrySize); - for (auto it = regularImportEntries.begin(); it != regularImportEntries.end(); ++it) { - auto *entry = it->second; - panda::pandasm::LiteralArray::Literal localName = { - .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName.Mutf8()}; - moduleLiteralArray.emplace_back(localName); - panda::pandasm::LiteralArray::Literal importName = { - .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->importName.Mutf8()}; - moduleLiteralArray.emplace_back(importName); - panda::pandasm::LiteralArray::Literal moduleRequest = { - .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, - .value_ = static_cast(entry->moduleRequest)}; - moduleLiteralArray.emplace_back(moduleRequest); - } -} - -void FunctionEmitter::GenNamespaceImportEntries(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray) -{ - auto &namespaceImportEntries = moduleRecord->GetNamespaceImportEntries(); - panda::pandasm::LiteralArray::Literal entrySize = { - .tag_ = panda::panda_file::LiteralTag::INTEGER, - .value_ = static_cast(namespaceImportEntries.size())}; - moduleLiteralArray.emplace_back(entrySize); - for (const auto *entry : namespaceImportEntries) { - panda::pandasm::LiteralArray::Literal localName = { - .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName.Mutf8()}; - moduleLiteralArray.emplace_back(localName); - panda::pandasm::LiteralArray::Literal moduleRequest = { - .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, - .value_ = static_cast(entry->moduleRequest)}; - moduleLiteralArray.emplace_back(moduleRequest); - } -} - -void FunctionEmitter::GenLocalExportEntries(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray) -{ - auto &localExportEntries = moduleRecord->GetLocalExportEntries(); - panda::pandasm::LiteralArray::Literal entrySize = { - .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(localExportEntries.size())}; - moduleLiteralArray.emplace_back(entrySize); - for (auto it = localExportEntries.begin(); it != localExportEntries.end(); ++it) { - auto *entry = it->second; - panda::pandasm::LiteralArray::Literal localName = { - .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName.Mutf8()}; - moduleLiteralArray.emplace_back(localName); - panda::pandasm::LiteralArray::Literal exportName = { - .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->exportName.Mutf8()}; - moduleLiteralArray.emplace_back(exportName); - } -} - -void FunctionEmitter::GenIndirectExportEntries(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray) -{ - auto &indirectExportEntries = moduleRecord->GetIndirectExportEntries(); - panda::pandasm::LiteralArray::Literal entrySize = { - .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(indirectExportEntries.size())}; - moduleLiteralArray.emplace_back(entrySize); - for (const auto *entry : indirectExportEntries) { - panda::pandasm::LiteralArray::Literal exportName = { - .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->exportName.Mutf8()}; - moduleLiteralArray.emplace_back(exportName); - panda::pandasm::LiteralArray::Literal importName = { - .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->importName.Mutf8()}; - moduleLiteralArray.emplace_back(importName); - panda::pandasm::LiteralArray::Literal moduleRequest = { - .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, - .value_ = static_cast(entry->moduleRequest)}; - moduleLiteralArray.emplace_back(moduleRequest); - } -} - -void FunctionEmitter::GenStarExportEntries(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray) -{ - auto &starExportEntries = moduleRecord->GetStarExportEntries(); - panda::pandasm::LiteralArray::Literal entrySize = { - .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(starExportEntries.size())}; - moduleLiteralArray.emplace_back(entrySize); - for (const auto *entry : starExportEntries) { - panda::pandasm::LiteralArray::Literal moduleRequest = { - .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, - .value_ = static_cast(entry->moduleRequest)}; - moduleLiteralArray.emplace_back(moduleRequest); - } -} - -void FunctionEmitter::GenSourceTextModuleRecord() -{ - if (!pg_->TopScope()->IsModuleScope()) { - return; - } - - auto *moduleRecord = pg_->TopScope()->AsModuleScope()->GetModuleRecord(); - auto &[idx, array] = literalBuffers_.emplace_back(); - idx = pg_->ModuleBuffIndex(); - - GenModuleRequests(moduleRecord, array); - GenRegularImportEntries(moduleRecord, array); - GenNamespaceImportEntries(moduleRecord, array); - GenLocalExportEntries(moduleRecord, array); - GenIndirectExportEntries(moduleRecord, array); - GenStarExportEntries(moduleRecord, array); -} - void FunctionEmitter::GenSourceFileDebugInfo() { func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()}; @@ -489,7 +359,6 @@ Emitter::Emitter(const CompilerContext *context) prog_->function_table.reserve(context->Binder()->Functions().size()); GenESAnnoatationRecord(); - GenerateESModuleRecord(context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); } Emitter::~Emitter() @@ -505,30 +374,6 @@ void Emitter::GenESAnnoatationRecord() prog_->record_table.emplace(annotationRecord.name, std::move(annotationRecord)); } -void Emitter::GenerateESModuleRecord(bool isModule) -{ - if (isModule) { - auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT); - ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC); - prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord)); - } -} - -void Emitter::AddSourceTextModuleRecord(PandaGen *pg) -{ - ASSERT(pg->TopScope()->IsModuleScope()); - auto iter = prog_->record_table.find("_ESModuleRecord"); - if (iter != prog_->record_table.end()) { - auto &rec = iter->second; - auto moduleIdxField = panda::pandasm::Field(LANG_EXT); - moduleIdxField.name = std::string {pg->Binder()->Program()->SourceFile()}; - moduleIdxField.type = panda::pandasm::Type("u32", 0); - moduleIdxField.metadata->SetValue(panda::pandasm::ScalarValue::Create( - static_cast(pg->ModuleBuffIndex()))); - rec.field_list.emplace_back(std::move(moduleIdxField)); - } -} - void Emitter::AddFunction(FunctionEmitter *func) { std::lock_guard lock(m_); @@ -546,6 +391,26 @@ void Emitter::AddFunction(FunctionEmitter *func) prog_->function_table.emplace(function->name, std::move(*function)); } +void Emitter::AddSourceTextModuleRecord(ModuleRecordEmitter *module, const CompilerContext *context) +{ + std::lock_guard lock(m_); + + auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT); + ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC); + + auto moduleIdxField = panda::pandasm::Field(LANG_EXT); + moduleIdxField.name = std::string {context->Binder()->Program()->SourceFile()}; + moduleIdxField.type = panda::pandasm::Type("u32", 0); + moduleIdxField.metadata->SetValue(panda::pandasm::ScalarValue::Create( + static_cast(module->Index()))); + ecmaModuleRecord.field_list.emplace_back(std::move(moduleIdxField)); + prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord)); + + auto &moduleLiteralsBuffer = module->Buffer(); + auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(moduleLiteralsBuffer)); + prog_->literalarray_table.emplace(std::to_string(module->Index()), std::move(literalArrayInstance)); +} + void Emitter::DumpAsm(const panda::pandasm::Program *prog) { auto &ss = std::cout; diff --git a/es2panda/compiler/core/emitter.h b/es2panda/compiler/core/emitter/emitter.h similarity index 70% rename from es2panda/compiler/core/emitter.h rename to es2panda/compiler/core/emitter/emitter.h index aa607d8cc0..27f22a0490 100644 --- a/es2panda/compiler/core/emitter.h +++ b/es2panda/compiler/core/emitter/emitter.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,6 @@ class Statement; namespace panda::es2panda::binder { class Scope; -class SourceTextModuleRecord; } // namespace panda::es2panda::binder namespace panda::es2panda::compiler { @@ -87,26 +87,45 @@ private: void GenLiteralBuffers(); void GenBufferLiterals(const LiteralBuffer *buff); - void GenModuleRequests(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray); - void GenRegularImportEntries(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray); - void GenNamespaceImportEntries(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray); - void GenLocalExportEntries(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray); - void GenIndirectExportEntries(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray); - void GenStarExportEntries(binder::SourceTextModuleRecord *moduleRecord, - std::vector &moduleLiteralArray); - void GenSourceTextModuleRecord(); - const PandaGen *pg_; panda::pandasm::Function *func_ {}; ArenaVector>> literalBuffers_; size_t offset_ {0}; }; +class ModuleRecordEmitter { +public: + explicit ModuleRecordEmitter(parser::SourceTextModuleRecord *moduleRecord, int32_t bufferIdx) + : moduleRecord_(moduleRecord), bufferIdx_(bufferIdx) {} + ~ModuleRecordEmitter() = default; + NO_COPY_SEMANTIC(ModuleRecordEmitter); + NO_MOVE_SEMANTIC(ModuleRecordEmitter); + + int32_t Index() const + { + return bufferIdx_; + } + + auto &Buffer() + { + return buffer_; + } + + void Generate(); + +private: + void GenModuleRequests(); + void GenRegularImportEntries(); + void GenNamespaceImportEntries(); + void GenLocalExportEntries(); + void GenIndirectExportEntries(); + void GenStarExportEntries(); + + parser::SourceTextModuleRecord *moduleRecord_; + int32_t bufferIdx_ {}; + std::vector buffer_; +}; + class Emitter { public: explicit Emitter(const CompilerContext *context); @@ -115,13 +134,12 @@ public: NO_MOVE_SEMANTIC(Emitter); void AddFunction(FunctionEmitter *func); - void AddSourceTextModuleRecord(PandaGen *pg); + void AddSourceTextModuleRecord(ModuleRecordEmitter *module, const CompilerContext *context); static void DumpAsm(const panda::pandasm::Program *prog); panda::pandasm::Program *Finalize(bool dumpDebugInfo); private: void GenESAnnoatationRecord(); - void GenerateESModuleRecord(bool isModule); std::mutex m_; panda::pandasm::Program *prog_; diff --git a/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp b/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp new file mode 100644 index 0000000000..d3f6ffdd96 --- /dev/null +++ b/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp @@ -0,0 +1,140 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "emitter.h" + +namespace panda::es2panda::compiler { + +void ModuleRecordEmitter::GenModuleRequests() +{ + ASSERT(moduleRecord_ != nullptr); + auto &moduleRequests = moduleRecord_->GetModuleRequests(); + panda::pandasm::LiteralArray::Literal moduleSize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(moduleRequests.size())}; + buffer_.emplace_back(moduleSize); + for (auto request : moduleRequests) { + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = request.Mutf8()}; + buffer_.emplace_back(moduleRequest); + } +} + +void ModuleRecordEmitter::GenRegularImportEntries() +{ + ASSERT(moduleRecord_ != nullptr); + auto ®ularImportEntries = moduleRecord_->GetRegularImportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, + .value_ = static_cast(regularImportEntries.size())}; + buffer_.emplace_back(entrySize); + for (auto it = regularImportEntries.begin(); it != regularImportEntries.end(); ++it) { + auto *entry = it->second; + panda::pandasm::LiteralArray::Literal localName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName_.Mutf8()}; + buffer_.emplace_back(localName); + panda::pandasm::LiteralArray::Literal importName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->importName_.Mutf8()}; + buffer_.emplace_back(importName); + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequestIdx_)}; + buffer_.emplace_back(moduleRequest); + } +} + +void ModuleRecordEmitter::GenNamespaceImportEntries() +{ + ASSERT(moduleRecord_ != nullptr); + auto &namespaceImportEntries = moduleRecord_->GetNamespaceImportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, + .value_ = static_cast(namespaceImportEntries.size())}; + buffer_.emplace_back(entrySize); + for (const auto *entry : namespaceImportEntries) { + panda::pandasm::LiteralArray::Literal localName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName_.Mutf8()}; + buffer_.emplace_back(localName); + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequestIdx_)}; + buffer_.emplace_back(moduleRequest); + } +} + +void ModuleRecordEmitter::GenLocalExportEntries() +{ + ASSERT(moduleRecord_ != nullptr); + auto &localExportEntries = moduleRecord_->GetLocalExportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(localExportEntries.size())}; + buffer_.emplace_back(entrySize); + for (auto it = localExportEntries.begin(); it != localExportEntries.end(); ++it) { + auto *entry = it->second; + panda::pandasm::LiteralArray::Literal localName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName_.Mutf8()}; + buffer_.emplace_back(localName); + panda::pandasm::LiteralArray::Literal exportName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->exportName_.Mutf8()}; + buffer_.emplace_back(exportName); + } +} + +void ModuleRecordEmitter::GenIndirectExportEntries() +{ + ASSERT(moduleRecord_ != nullptr); + auto &indirectExportEntries = moduleRecord_->GetIndirectExportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(indirectExportEntries.size())}; + buffer_.emplace_back(entrySize); + for (const auto *entry : indirectExportEntries) { + panda::pandasm::LiteralArray::Literal exportName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->exportName_.Mutf8()}; + buffer_.emplace_back(exportName); + panda::pandasm::LiteralArray::Literal importName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->importName_.Mutf8()}; + buffer_.emplace_back(importName); + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequestIdx_)}; + buffer_.emplace_back(moduleRequest); + } +} + +void ModuleRecordEmitter::GenStarExportEntries() +{ + ASSERT(moduleRecord_ != nullptr); + auto &starExportEntries = moduleRecord_->GetStarExportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(starExportEntries.size())}; + buffer_.emplace_back(entrySize); + for (const auto *entry : starExportEntries) { + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequestIdx_)}; + buffer_.emplace_back(moduleRequest); + } +} + +void ModuleRecordEmitter::Generate() +{ + GenModuleRequests(); + GenRegularImportEntries(); + GenNamespaceImportEntries(); + GenLocalExportEntries(); + GenIndirectExportEntries(); + GenStarExportEntries(); +} + +} // namespace panda::es2panda::compiler diff --git a/es2panda/compiler/core/pandagen.cpp b/es2panda/compiler/core/pandagen.cpp index d9b31d1142..4a268c7068 100644 --- a/es2panda/compiler/core/pandagen.cpp +++ b/es2panda/compiler/core/pandagen.cpp @@ -185,13 +185,6 @@ int32_t PandaGen::AddLiteralBuffer(LiteralBuffer *buf) return buf->Index(); } -void PandaGen::SetModuleRecordBufferIndex() -{ - if (topScope_->IsModuleScope()) { - moduleBuffIndex_ = context_->NewLiteralIndex(); - } -} - int32_t PandaGen::AddLexicalVarNamesForDebugInfo(ArenaMap &lexicalVars) { auto *buf = NewLiteralBuffer(); @@ -1414,7 +1407,7 @@ void PandaGen::DefineClassWithBuffer(const ir::AstNode *node, const util::String void PandaGen::LoadModuleVariable(const ir::AstNode *node, const util::StringView &name, bool isLocalExport) { - ra_.Emit(node, name, isLocalExport ? static_cast(1) : static_cast(0)); + ra_.Emit(node, name, isLocalExport ? static_cast(1) : static_cast(0)); strings_.insert(name); } diff --git a/es2panda/compiler/core/pandagen.h b/es2panda/compiler/core/pandagen.h index 21c0ba0bea..10b0dafc5c 100644 --- a/es2panda/compiler/core/pandagen.h +++ b/es2panda/compiler/core/pandagen.h @@ -174,11 +174,6 @@ public: return buffStorage_; } - int32_t ModuleBuffIndex() const - { - return moduleBuffIndex_; - } - uint32_t IcSize() const { return ic_.Size(); @@ -210,8 +205,6 @@ public: LiteralBuffer *NewLiteralBuffer(); int32_t AddLiteralBuffer(LiteralBuffer *buf); - void SetModuleRecordBufferIndex(); - int32_t AddLexicalVarNamesForDebugInfo(ArenaMap &lexicalMap); void InitializeLexEnv(const ir::AstNode *node, VReg lexEnv); @@ -435,7 +428,6 @@ private: RegAllocator ra_; RangeRegAllocator rra_; - int32_t moduleBuffIndex_ {-1}; uint32_t usedRegs_ {0}; uint32_t totalRegs_ {0}; friend class ScopeContext; diff --git a/es2panda/compiler/core/regScope.cpp b/es2panda/compiler/core/regScope.cpp index aa617cb64c..196a019015 100644 --- a/es2panda/compiler/core/regScope.cpp +++ b/es2panda/compiler/core/regScope.cpp @@ -16,7 +16,6 @@ #include "regScope.h" #include -#include #include #include #include diff --git a/es2panda/ir/module/exportDefaultDeclaration.cpp b/es2panda/ir/module/exportDefaultDeclaration.cpp index 082be0b702..e2208de1fe 100644 --- a/es2panda/ir/module/exportDefaultDeclaration.cpp +++ b/es2panda/ir/module/exportDefaultDeclaration.cpp @@ -37,7 +37,7 @@ void ExportDefaultDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) if (!decl_->IsFunctionDeclaration() && !decl_->IsClassDeclaration()) { // export default without [Function Declaration] & [Class Declaration] // is [ExportAssignment]. e.g. export default 42 (42 be exported as [default]) - pg->StoreModuleVariable(this, "*default*"); + pg->StoreModuleVariable(this, parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME); } } diff --git a/es2panda/ir/statements/classDeclaration.cpp b/es2panda/ir/statements/classDeclaration.cpp index 672d154dbc..ed3b591447 100644 --- a/es2panda/ir/statements/classDeclaration.cpp +++ b/es2panda/ir/statements/classDeclaration.cpp @@ -48,7 +48,7 @@ void ClassDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const } else { ASSERT(this->Parent()->IsExportDefaultDeclaration() && pg->Scope()->IsModuleScope()); def_->Compile(pg); - pg->StoreModuleVariable(def_, util::StringView("*default*")); + pg->StoreModuleVariable(def_, parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME); } } diff --git a/es2panda/parser/context/parserContext.h b/es2panda/parser/context/parserContext.h index 95d9743ee5..790e60518f 100644 --- a/es2panda/parser/context/parserContext.h +++ b/es2panda/parser/context/parserContext.h @@ -46,7 +46,7 @@ enum class ParserStatus { IN_ITERATION = (1 << 14), IN_LABELED = (1 << 15), - EXPORT_DEFAULT_REACHED = (1 << 16), + EXPORT_REACHED = (1 << 16), HAS_COMPLEX_PARAM = (1 << 17), IN_SWITCH = (1 << 18), diff --git a/es2panda/parser/module/module.cpp b/es2panda/parser/module/module.cpp new file mode 100644 index 0000000000..1565bf8535 --- /dev/null +++ b/es2panda/parser/module/module.cpp @@ -0,0 +1,164 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "module.h" + +namespace panda::es2panda::parser { + + int SourceTextModuleRecord::AddModuleRequest(const util::StringView source) + { + ASSERT(!source.Empty()); + int moduleRequestsSize = static_cast(moduleRequestsMap_.size()); + if (moduleRequestsMap_.find(source) == moduleRequestsMap_.end()) { + moduleRequests_.emplace_back(source); + } + auto insertedRes = moduleRequestsMap_.insert(std::make_pair(source, moduleRequestsSize)); + return insertedRes.first->second; + } + + // import x from 'test.js'; + // import {x} from 'test.js'; + // import {x as y} from 'test.js'; + // import defaultExport from 'test.js' + void SourceTextModuleRecord::AddImportEntry(SourceTextModuleRecord::ImportEntry *entry) + { + ASSERT(!entry->importName_.Empty()); + ASSERT(!entry->localName_.Empty()); + ASSERT(entry->moduleRequestIdx_ != -1); + regularImportEntries_.insert(std::make_pair(entry->localName_, entry)); + // the implicit indirect exports should be insert into indirectExportsEntries + // when add an ImportEntry. + // e.g. export { x }; import { x } from 'test.js' + ConvertLocalExportsToIndirect(entry); + } + + // import * as x from 'test.js'; + void SourceTextModuleRecord::AddStarImportEntry(SourceTextModuleRecord::ImportEntry *entry) + { + ASSERT(!entry->localName_.Empty()); + ASSERT(entry->importName_.Empty()); + ASSERT(entry->moduleRequestIdx_ != -1); + namespaceImportEntries_.push_back(entry); + } + + // export {x}; + // export {x as y}; + // export VariableStatement + // export Declaration + // export default ... + bool SourceTextModuleRecord::AddLocalExportEntry(SourceTextModuleRecord::ExportEntry *entry) + { + ASSERT(entry->importName_.Empty()); + ASSERT(!entry->localName_.Empty()); + ASSERT(!entry->exportName_.Empty()); + ASSERT(entry->moduleRequestIdx_ == -1); + + // the implicit indirect exports should be insert into indirectExportsEntries + // when add an ExportEntry. + // e.g. import { x } from 'test.js'; export { x } + if (ConvertLocalExportsToIndirect(entry)) { + return true; + } + if (CheckDuplicateExports(entry->exportName_)) { + localExportEntries_.insert(std::make_pair(entry->localName_, entry)); + return true; + } + return false; + } + + // export {x} from 'test.js'; + // export {x as y} from 'test.js'; + // import { x } from 'test.js'; export { x }; + bool SourceTextModuleRecord::AddIndirectExportEntry(SourceTextModuleRecord::ExportEntry *entry) + { + ASSERT(!entry->importName_.Empty()); + ASSERT(!entry->exportName_.Empty()); + ASSERT(entry->localName_.Empty()); + ASSERT(entry->moduleRequestIdx_ != -1); + if (CheckDuplicateExports(entry->exportName_)) { + indirectExportEntries_.push_back(entry); + return true; + } + return false; + } + + // export * from 'test.js'; + void SourceTextModuleRecord::AddStarExportEntry(SourceTextModuleRecord::ExportEntry *entry) + { + ASSERT(entry->importName_.Empty()); + ASSERT(entry->localName_.Empty()); + ASSERT(entry->exportName_.Empty()); + ASSERT(entry->moduleRequestIdx_ != -1); + starExportEntries_.push_back(entry); + } + + bool SourceTextModuleRecord::CheckDuplicateExports(util::StringView exportName) + { + for (auto const &entryUnit : localExportEntries_) { + const SourceTextModuleRecord::ExportEntry *e = entryUnit.second; + if (exportName == e->exportName_) { + return false; + } + } + + for (const auto *e : indirectExportEntries_) { + if (exportName == e->exportName_) { + return false; + } + } + + return true; + } + + bool SourceTextModuleRecord::ConvertLocalExportsToIndirect(SourceTextModuleRecord::ExportEntry *exportEntry) + { + ASSERT(!exportEntry->localName_.Empty()); + auto importEntry = regularImportEntries_.find(exportEntry->localName_); + if (importEntry != regularImportEntries_.end()) { + ASSERT(exportEntry->importName_.Empty()); + ASSERT(exportEntry->moduleRequestIdx_ == -1); + ASSERT(!importEntry->second->importName_.Empty()); + ASSERT(importEntry->second->moduleRequestIdx_ != -1); + exportEntry->importName_ = importEntry->second->importName_; + exportEntry->moduleRequestIdx_ = importEntry->second->moduleRequestIdx_; + exportEntry->localName_ = util::StringView(""); + return AddIndirectExportEntry(exportEntry); + } + return false; + } + + void SourceTextModuleRecord::ConvertLocalExportsToIndirect(SourceTextModuleRecord::ImportEntry *importEntry) + { + ASSERT(!importEntry->localName_.Empty()); + auto range = localExportEntries_.equal_range(importEntry->localName_); + // not found implicit indirect + if (range.first == range.second) { + return; + } + + for (auto it = range.first; it != range.second; ++it) { + SourceTextModuleRecord::ExportEntry *exportEntry = it->second; + ASSERT(exportEntry->importName_.Empty()); + ASSERT(exportEntry->moduleRequestIdx_ == -1); + ASSERT(!importEntry->importName_.Empty()); + ASSERT(importEntry->moduleRequestIdx_ != -1); + exportEntry->importName_ = importEntry->importName_; + exportEntry->moduleRequestIdx_ = importEntry->moduleRequestIdx_; + exportEntry->localName_ = util::StringView(""); + indirectExportEntries_.push_back(exportEntry); + } + localExportEntries_.erase(range.first, range.second); + } +} // namespace panda::es2panda::parser diff --git a/es2panda/binder/module.h b/es2panda/parser/module/module.h similarity index 36% rename from es2panda/binder/module.h rename to es2panda/parser/module/module.h index be3797c9f3..fa301218b2 100644 --- a/es2panda/binder/module.h +++ b/es2panda/parser/module/module.h @@ -13,19 +13,16 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_SCOPES_MODULE_H -#define ES2PANDA_COMPILER_SCOPES_MODULE_H +#ifndef ES2PANDA_PARSER_CORE_MODULE_H +#define ES2PANDA_PARSER_CORE_MODULE_H -#include #include -namespace panda::es2panda::ir { -class AstNode; -} // namespace panda::es2panda::ir - namespace panda::es2panda::binder { - class ModuleScope; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::parser { class SourceTextModuleRecord { public: @@ -45,81 +42,55 @@ class SourceTextModuleRecord { NO_COPY_SEMANTIC(SourceTextModuleRecord); NO_MOVE_SEMANTIC(SourceTextModuleRecord); - struct Entry { - lexer::SourcePosition position; - const ir::AstNode *moduleNode; - int moduleRequest; - util::StringView exportName; - util::StringView localName; - util::StringView importName; - - explicit Entry(lexer::SourcePosition pos) - : position(pos), - moduleNode(nullptr), - moduleRequest(-1) {} + struct ImportEntry { + int moduleRequestIdx_; + util::StringView localName_; + util::StringView importName_; + + ImportEntry(const util::StringView localName, const util::StringView importName, int moduleRequestIdx) + : moduleRequestIdx_(moduleRequestIdx), localName_(localName), importName_(importName) {} + ImportEntry(const util::StringView localName, int moduleRequestIdx) + : moduleRequestIdx_(moduleRequestIdx), localName_(localName) {} }; - struct ModuleRequest { - int idx; - int pos; - ModuleRequest(int idx, int pos) - : idx(idx), pos(pos) {} + struct ExportEntry { + int moduleRequestIdx_; + util::StringView exportName_; + util::StringView localName_; + util::StringView importName_; + + ExportEntry(int moduleRequest) : moduleRequestIdx_(moduleRequest) {} + ExportEntry(const util::StringView exportName, const util::StringView localName) + : moduleRequestIdx_(-1), exportName_(exportName), localName_(localName) {} + ExportEntry(const util::StringView exportName, const util::StringView importName, int moduleRequest) + : moduleRequestIdx_(moduleRequest), exportName_(exportName) + { + importName_ = importName; + } }; - // import x from 'test.js'; - // import {x} from 'test.js'; - // import {x as y} from 'test.js'; - // import defaultExport from 'test.js' - void AddImportEntry(const util::StringView importName, - const util::StringView localName, - const util::StringView moduleRequest, - const lexer::SourcePosition pos, - const lexer::SourcePosition sourcePos); - - // import 'test.js' - // import {} from 'test.js' - // export {} from 'test.js' - void AddEmptyImportEntry(const util::StringView moduleRequest, const lexer::SourcePosition sourcePos); - - // import * as x from 'test.js'; - void AddStarImportEntry(const ir::AstNode *moduleNode, - const util::StringView localName, - const util::StringView moduleRequest, - const lexer::SourcePosition pos, - const lexer::SourcePosition sourcePos); - - // export {x}; - // export {x as y}; - // export VariableStatement - // export Declaration - // export default ... - void AddLocalExportEntry(const util::StringView exportName, - const util::StringView localName, - const lexer::SourcePosition pos); - - // export {x} from 'test.js'; - // export {x as y} from 'test.js'; - // import { x } from 'test.js'; export { x } - void AddIndirectExportEntry(const util::StringView importName, - const util::StringView exportName, - const util::StringView moduleRequest, - const lexer::SourcePosition pos, - const lexer::SourcePosition sourcePos); - - // export * from 'test.js'; - void AddStarExportEntry(const util::StringView moduleRequest, - const lexer::SourcePosition pos, - const lexer::SourcePosition sourcePos); - - bool ValidateModuleRecordEntries(ModuleScope *moduleScope, - std::string &errorMessage, - lexer::SourcePosition &errorPos); - - void SetModuleEnvironment(ModuleScope *moduleScope); - - using ModuleRequestMap = ArenaMap; - using LocalExportEntryMap = ArenaMultiMap; - using RegularImportEntryMap = ArenaMap; + template + T *NewEntry(Args &&... args) + { + return allocator_->New(std::forward(args)...); + } + + int AddModuleRequest(const util::StringView source); + void AddImportEntry(ImportEntry *entry); + void AddStarImportEntry(ImportEntry *entry); + bool AddLocalExportEntry(ExportEntry *entry); + bool AddIndirectExportEntry(ExportEntry *entry); + void AddStarExportEntry(ExportEntry *entry); + + bool ConvertLocalExportsToIndirect(ExportEntry *exportEntry); + void ConvertLocalExportsToIndirect(ImportEntry *importEntry); + + using ModuleRequestList = ArenaVector; + using ModuleRequestMap = ArenaMap; + using LocalExportEntryMap = ArenaMultiMap; + using RegularImportEntryMap = ArenaMap; + using NamespaceImportEntryList = ArenaVector; + using SpecialExportEntryList = ArenaVector; const ArenaVector &GetModuleRequests() const { @@ -136,41 +107,38 @@ class SourceTextModuleRecord { return regularImportEntries_; } - const ArenaVector &GetNamespaceImportEntries() const + const NamespaceImportEntryList &GetNamespaceImportEntries() const { return namespaceImportEntries_; } - const ArenaVector &GetStarExportEntries() const + const SpecialExportEntryList &GetStarExportEntries() const { return starExportEntries_; } - const ArenaVector &GetIndirectExportEntries() const + const SpecialExportEntryList &GetIndirectExportEntries() const { return indirectExportEntries_; } - private: - int AddModuleRequest(const util::StringView source, lexer::SourcePosition sourcePos); - void SetLocalExportEntriesVariables(ModuleScope *moduleScope); - void SetNameSpaceImportInitialized(ModuleScope *moduleScope); - - const Entry *SearchDupExport(); + static constexpr std::string_view DEFAULT_LOCAL_NAME= "*default*"; + static constexpr std::string_view DEFAULT_EXTERNAL_NAME = "default"; + static constexpr std::string_view ANONY_NAMESPACE_NAME = "=ens"; - const Entry *NextDuplicateExportEntry(const Entry *entry, - const Entry *duplicate, - ArenaMap &exportNameEntries); + private: + bool CheckDuplicateExports(util::StringView exportName); ArenaAllocator *allocator_; ModuleRequestMap moduleRequestsMap_; - ArenaVector moduleRequests_; + ModuleRequestList moduleRequests_; LocalExportEntryMap localExportEntries_; RegularImportEntryMap regularImportEntries_; - ArenaVector namespaceImportEntries_; - ArenaVector starExportEntries_; - ArenaVector indirectExportEntries_; + NamespaceImportEntryList namespaceImportEntries_; + SpecialExportEntryList starExportEntries_; + SpecialExportEntryList indirectExportEntries_; }; -} // namespace panda::es2panda::binder +} // namespace panda::es2panda::parser + #endif \ No newline at end of file diff --git a/es2panda/parser/parserFlags.h b/es2panda/parser/parserFlags.h index bb64a73ee2..48f1020f09 100644 --- a/es2panda/parser/parserFlags.h +++ b/es2panda/parser/parserFlags.h @@ -39,6 +39,7 @@ enum class VariableParsingFlags { LET = (1 << 4), CONST = (1 << 5), STOP_AT_IN = (1 << 6), + EXPORTED = (1 << 7), }; DEFINE_BITOPS(VariableParsingFlags) diff --git a/es2panda/parser/parserImpl.cpp b/es2panda/parser/parserImpl.cpp index 82886c7942..83da26513a 100644 --- a/es2panda/parser/parserImpl.cpp +++ b/es2panda/parser/parserImpl.cpp @@ -137,18 +137,6 @@ void ParserImpl::ParseProgram(ScriptKind kind) Binder()->GetScope()->BindNode(blockStmt); blockStmt->SetRange({startLoc, lexer_->GetToken().End()}); - if (kind == ScriptKind::MODULE) { - auto *moduleRecord = GetSourceTextModuleRecord(); - ASSERT(moduleRecord != nullptr); - std::string errorMessage = ""; - lexer::SourcePosition errorPos; - if (!moduleRecord->ValidateModuleRecordEntries(Binder()->TopScope()->AsModuleScope(), - errorMessage, errorPos)) { - ThrowSyntaxError(errorMessage.c_str(), errorPos); - } - moduleRecord->SetModuleEnvironment(Binder()->TopScope()->AsModuleScope()); - } - program_.SetAst(blockStmt); Binder()->IdentifierAnalysis(); } @@ -3257,4 +3245,9 @@ ScriptExtension ParserImpl::Extension() const return program_.Extension(); } +parser::SourceTextModuleRecord *ParserImpl::GetSourceTextModuleRecord() +{ + return Binder()->Program()->ModuleRecord(); +} + } // namespace panda::es2panda::parser diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index dd4ab934c5..3381cd021c 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -117,10 +118,6 @@ enum class MethodDefinitionKind; enum class ModifierFlags; } // namespace panda::es2panda::ir -namespace panda::es2panda::binder { -class SourceTextModuleRecord; -} // namespace panda::es2panda::binder - namespace panda::es2panda::parser { class Program; @@ -400,12 +397,11 @@ private: void AddImportEntryItem(const ir::StringLiteral *source, const ArenaVector *specifiers); void AddExportNamedEntryItem(const ArenaVector &specifiers, const ir::StringLiteral *source); - void AddExportStarEntryItem(const lexer::SourcePosition &startLoc, - const ir::StringLiteral *source, + void AddExportStarEntryItem(const lexer::SourcePosition &startLoc, const ir::StringLiteral *source, const ir::Identifier *exported); void AddExportDefaultEntryItem(const ir::AstNode *declNode); void AddExportLocalEntryItem(const ir::Statement *declNode); - binder::SourceTextModuleRecord *GetSourceTextModuleRecord(); + parser::SourceTextModuleRecord *GetSourceTextModuleRecord(); bool ParseDirective(ArenaVector *statements); void ParseDirectivePrologue(ArenaVector *statements); @@ -435,7 +431,7 @@ private: ir::Statement *ParseFunctionStatement(StatementParsingFlags flags, bool isDeclare); ir::FunctionDeclaration *ParseFunctionDeclaration(bool canBeAnonymous = false, ParserStatus newStatus = ParserStatus::NO_OPTS, - bool isDeclare = false, bool isExported = false); + bool isDeclare = false); ir::Statement *ParseExportDeclaration(StatementParsingFlags flags, ArenaVector &&decorators); std::tuple ParseForInOf( ir::Expression *leftNode, ExpressionParseFlags exprFlags, bool isAwait); @@ -451,10 +447,8 @@ private: ir::ReturnStatement *ParseReturnStatement(); ir::ClassDeclaration *ParseClassStatement(StatementParsingFlags flags, bool isDeclare, ArenaVector &&decorators, bool isAbstract = false); - ir::ClassDeclaration *ParseClassDeclaration(bool idRequired, - ArenaVector &&decorators, - bool isDeclare = false, - bool isAbstract = false, + ir::ClassDeclaration *ParseClassDeclaration(bool idRequired, ArenaVector &&decorators, + bool isDeclare = false, bool isAbstract = false, bool isExported = false); ir::TSTypeAliasDeclaration *ParseTsTypeAliasDeclaration(bool isDeclare); ir::TSEnumDeclaration *ParseEnumMembers(ir::Identifier *key, const lexer::SourcePosition &enumStart, bool isConst); @@ -469,17 +463,18 @@ private: void ValidateDeclaratorId(); ir::VariableDeclarator *ParseVariableDeclaratorInitializer(ir::Expression *init, VariableParsingFlags flags, const lexer::SourcePosition &startLoc, bool isDeclare); - ir::VariableDeclarator *ParseVariableDeclarator(VariableParsingFlags flags, - bool isDeclare, bool isExported = false); + ir::VariableDeclarator *ParseVariableDeclarator(VariableParsingFlags flags, bool isDeclare); ir::Statement *ParseVariableDeclaration(VariableParsingFlags flags = VariableParsingFlags::NO_OPTS, - bool isDeclare = false, bool isExported = false); + bool isDeclare = false); ir::WhileStatement *ParseWhileStatement(); ir::VariableDeclaration *ParseContextualLet(VariableParsingFlags flags, StatementParsingFlags stmFlags = StatementParsingFlags::ALLOW_LEXICAL, bool isDeclare = false); + util::StringView GetNamespaceExportInternalName() { - std::string name = "=ens" + std::to_string(namespaceExportCount_++); + std::string name = std::string(parser::SourceTextModuleRecord::ANONY_NAMESPACE_NAME) + + std::to_string(namespaceExportCount_++); util::UString internalName(name, Allocator()); return internalName.View(); } diff --git a/es2panda/parser/program/program.cpp b/es2panda/parser/program/program.cpp index 128c80dd13..717ba230d9 100644 --- a/es2panda/parser/program/program.cpp +++ b/es2panda/parser/program/program.cpp @@ -63,6 +63,10 @@ void Program::SetKind(ScriptKind kind) { kind_ = kind; binder_->InitTopScope(); + + if (kind == ScriptKind::MODULE) { + moduleRecord_ = allocator_->New(Allocator()); + } } std::string Program::Dump() const diff --git a/es2panda/parser/program/program.h b/es2panda/parser/program/program.h index c32afee7a9..65db646333 100644 --- a/es2panda/parser/program/program.h +++ b/es2panda/parser/program/program.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "es2panda.h" @@ -68,6 +69,11 @@ public: return kind_; } + SourceTextModuleRecord *ModuleRecord() const + { + return moduleRecord_; + } + util::StringView SourceCode() const { return sourceCode_.View(); @@ -117,6 +123,7 @@ private: ScriptKind kind_ {}; ScriptExtension extension_ {}; lexer::LineIndex lineIndex_ {}; + SourceTextModuleRecord *moduleRecord_ {nullptr}; }; } // namespace panda::es2panda::parser diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index b9489ece06..6d08ae98aa 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -521,13 +521,13 @@ ir::ClassDeclaration *ParserImpl::ParseClassDeclaration(bool idRequired, ArenaVe lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ir::ClassDefinition *classDefinition = ParseClassDefinition(true, idRequired, isDeclare, isAbstract); - auto *decl = - Binder()->AddDecl(classDefinition->Ident() == nullptr ? - startLoc : classDefinition->Ident()->Start(), - classDefinition->Ident() == nullptr ? - util::StringView("*default*") : classDefinition->Ident()->Name(), - isExported ? - binder::DeclModuleStatus::EXPORT : binder::DeclModuleStatus::NONE); + auto location = classDefinition->Ident() == nullptr ? startLoc : classDefinition->Ident()->Start(); + auto className = classDefinition->Ident() == nullptr ? parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME : + classDefinition->Ident()->Name(); + + binder::DeclarationFlags flag = isExported ? binder::DeclarationFlags::EXPORT : binder::DeclarationFlags::NONE; + auto *decl = Binder()->AddDecl(location, flag, className); + decl->BindNode(classDefinition); lexer::SourcePosition endLoc = classDefinition->End(); @@ -960,7 +960,7 @@ ir::DoWhileStatement *ParserImpl::ParseDoWhileStatement() } ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymous, ParserStatus newStatus, - bool isDeclare, bool isExported) + bool isDeclare) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); @@ -985,12 +985,12 @@ ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymou auto *funcDecl = AllocNode(func); funcDecl->SetRange(func->Range()); - Binder()->AddDecl(startLoc, - Allocator(), - util::StringView("*default*"), - func, - isExported ? - binder::DeclModuleStatus::EXPORT : binder::DeclModuleStatus::NONE); + + binder::DeclarationFlags declflag = newStatus & ParserStatus::EXPORT_REACHED ? + binder::DeclarationFlags::EXPORT : binder::DeclarationFlags::NONE; + Binder()->AddDecl(startLoc, declflag, Allocator(), + parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME, func); + return funcDecl; } @@ -1016,12 +1016,9 @@ ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymou funcDecl->SetRange(func->Range()); if (!func->IsOverload()) { - Binder()->AddDecl(identNode->Start(), - Allocator(), - ident, - func, - isExported ? - binder::DeclModuleStatus::EXPORT : binder::DeclModuleStatus::NONE); + binder::DeclarationFlags declflag = newStatus & ParserStatus::EXPORT_REACHED ? + binder::DeclarationFlags::EXPORT : binder::DeclarationFlags::NONE; + Binder()->AddDecl(identNode->Start(), declflag, Allocator(), ident, func); } else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); } @@ -1762,8 +1759,7 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclaratorInitializer(ir::Expre return declarator; } -ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags flags, - bool isDeclare, bool isExported) +ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags flags, bool isDeclare) { ir::Expression *init = nullptr; lexer::SourcePosition startLoc = lexer_->GetToken().Start(); @@ -1824,16 +1820,15 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags for (const auto *binding : bindings) { binder::Decl *decl = nullptr; - - binder::DeclModuleStatus moduleDeclkind - = isExported ? binder::DeclModuleStatus::EXPORT : binder::DeclModuleStatus::NONE; + binder::DeclarationFlags declflag = flags & VariableParsingFlags::EXPORTED ? + binder::DeclarationFlags::EXPORT : binder::DeclarationFlags::NONE; if (flags & VariableParsingFlags::VAR) { - decl = Binder()->AddDecl(startLoc, binding->Name(), moduleDeclkind); + decl = Binder()->AddDecl(startLoc, declflag, binding->Name()); } else if (flags & VariableParsingFlags::LET) { - decl = Binder()->AddDecl(startLoc, binding->Name(), moduleDeclkind); + decl = Binder()->AddDecl(startLoc, declflag, binding->Name()); } else { - decl = Binder()->AddDecl(startLoc, binding->Name(), moduleDeclkind); + decl = Binder()->AddDecl(startLoc, declflag, binding->Name()); } decl->BindNode(init); @@ -1842,7 +1837,7 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags return declarator; } -ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, bool isDeclare, bool isExported) +ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, bool isDeclare) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); @@ -1865,7 +1860,7 @@ ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, ArenaVector declarators(Allocator()->Adapter()); while (true) { - ir::VariableDeclarator *declarator = ParseVariableDeclarator(flags, isDeclare, isExported); + ir::VariableDeclarator *declarator = ParseVariableDeclarator(flags, isDeclare); declarators.push_back(declarator); @@ -1917,49 +1912,40 @@ ir::WhileStatement *ParserImpl::ParseWhileStatement() return whileStatement; } -binder::SourceTextModuleRecord *ParserImpl::GetSourceTextModuleRecord() -{ - return Binder()->TopScope()->AsModuleScope()->GetModuleRecord(); -} - void ParserImpl::AddImportEntryItem(const ir::StringLiteral *source, const ArenaVector *specifiers) { ASSERT(source != nullptr); - auto moduleRecord = GetSourceTextModuleRecord(); + auto *moduleRecord = GetSourceTextModuleRecord(); + ASSERT(moduleRecord != nullptr); + auto moduleRequestIdx = moduleRecord->AddModuleRequest(source->Str()); - if (specifiers == nullptr || specifiers->empty()) { - moduleRecord->AddEmptyImportEntry(source->Str(), source->Start()); + if (specifiers == nullptr) { return; } for (auto *it : *specifiers) { switch(it->Type()) { case ir::AstNodeType::IMPORT_DEFAULT_SPECIFIER: { - auto importDefault = it->AsImportDefaultSpecifier(); - auto defaultString = util::StringView("default"); - moduleRecord->AddImportEntry(defaultString, - importDefault->Local()->Name(), - source->Str(), - importDefault->Start(), - source->Start()); + auto localName = it->AsImportDefaultSpecifier()->Local()->Name(); + auto importName = parser::SourceTextModuleRecord::DEFAULT_EXTERNAL_NAME; + auto *entry = moduleRecord->NewEntry( + localName, importName, moduleRequestIdx); + moduleRecord->AddImportEntry(entry); break; } case ir::AstNodeType::IMPORT_NAMESPACE_SPECIFIER: { - auto namespaceSpecifier = it->AsImportNamespaceSpecifier(); - moduleRecord->AddStarImportEntry(it, - namespaceSpecifier->Local()->Name(), - source->Str(), - namespaceSpecifier->Start(), - source->Start()); + auto localName = it->AsImportNamespaceSpecifier()->Local()->Name(); + auto *entry = moduleRecord->NewEntry( + localName, moduleRequestIdx); + moduleRecord->AddStarImportEntry(entry); break; } case ir::AstNodeType::IMPORT_SPECIFIER: { - auto importSpecifier = it->AsImportSpecifier(); - moduleRecord->AddImportEntry(importSpecifier->Imported()->Name(), - importSpecifier->Local()->Name(), - source->Str(), - importSpecifier->Start(), - source->Start()); + auto localName = it->AsImportSpecifier()->Local()->Name(); + auto importName = it->AsImportSpecifier()->Imported()->Name(); + auto *entry = moduleRecord->NewEntry( + localName, importName, moduleRequestIdx); + moduleRecord->AddImportEntry(entry); break; } default: { @@ -1975,50 +1961,66 @@ void ParserImpl::AddExportNamedEntryItem(const ArenaVectorAddEmptyImportEntry(source->Str(), source->Start()); - } + auto moduleRequestIdx = moduleRecord->AddModuleRequest(source->Str()); for (auto *it : specifiers) { auto exportSpecifier = it->AsExportSpecifier(); - moduleRecord->AddIndirectExportEntry(exportSpecifier->Local()->Name(), - exportSpecifier->Exported()->Name(), - source->Str(), - exportSpecifier->Start(), - source->Start()); + auto importName = exportSpecifier->Local()->Name(); + auto exportName = exportSpecifier->Exported()->Name(); + auto *entry = moduleRecord->NewEntry( + exportName, importName, moduleRequestIdx); + if (!moduleRecord->AddIndirectExportEntry(entry)) { + ThrowSyntaxError("Duplicate export name of '" + exportName.Mutf8() + "'", + exportSpecifier->Start()); + } } } else { for (auto *it : specifiers) { auto exportSpecifier = it->AsExportSpecifier(); - moduleRecord->AddLocalExportEntry(exportSpecifier->Exported()->Name(), - exportSpecifier->Local()->Name(), - exportSpecifier->Start()); + auto exportName = exportSpecifier->Exported()->Name(); + auto localName = exportSpecifier->Local()->Name(); + auto *entry = moduleRecord->NewEntry(exportName, localName); + if(!moduleRecord->AddLocalExportEntry(entry)) { + ThrowSyntaxError("Duplicate export name of '" + exportName.Mutf8() + "'", + exportSpecifier->Start()); + } } } } -void ParserImpl::AddExportStarEntryItem(const lexer::SourcePosition &startLoc, - const ir::StringLiteral *source, +void ParserImpl::AddExportStarEntryItem(const lexer::SourcePosition &startLoc, const ir::StringLiteral *source, const ir::Identifier *exported) { - ASSERT(source != nullptr); auto moduleRecord = GetSourceTextModuleRecord(); + ASSERT(moduleRecord != nullptr); + ASSERT(source != nullptr); + auto moduleRequestIdx = moduleRecord->AddModuleRequest(source->Str()); if (exported != nullptr) { /* Transform [NamespaceExport] into [NamespaceImport] & [LocalExport] * e.g. export * as ns from 'test.js' * ---> * import * as [internalName] from 'test.js' - * export { [inter] as ns } + * export { [internalName] as ns } */ auto namespaceExportInternalName = GetNamespaceExportInternalName(); - Binder()->AddDecl(startLoc, namespaceExportInternalName, binder::DeclModuleStatus::NONE); - moduleRecord->AddStarImportEntry(exported, namespaceExportInternalName, source->Str(), - lexer::SourcePosition(), source->Start()); - moduleRecord->AddLocalExportEntry(exported->Name(), namespaceExportInternalName, exported->Start()); + auto *decl = Binder()->AddDecl(startLoc, binder::DeclarationFlags::EXPORT, + namespaceExportInternalName); + decl->BindNode(exported); + + auto *importEntry = moduleRecord->NewEntry( + namespaceExportInternalName, moduleRequestIdx); + auto *exportEntry = moduleRecord->NewEntry( + exported->Name(), namespaceExportInternalName); + moduleRecord->AddStarImportEntry(importEntry); + if(!moduleRecord->AddLocalExportEntry(exportEntry)) { + ThrowSyntaxError("Duplicate export name of '" + exported->Name().Mutf8() + "'", exported->Start()); + } + return; } - moduleRecord->AddStarExportEntry(source->Str(), startLoc, source->Start()); + auto *entry = moduleRecord->NewEntry(moduleRequestIdx); + moduleRecord->AddStarExportEntry(entry); } void ParserImpl::AddExportDefaultEntryItem(const ir::AstNode *declNode) @@ -2027,36 +2029,43 @@ void ParserImpl::AddExportDefaultEntryItem(const ir::AstNode *declNode) if (declNode->IsTSInterfaceDeclaration()) { return; } + auto moduleRecord = GetSourceTextModuleRecord(); - auto exportName = util::StringView("default"); + ASSERT(moduleRecord != nullptr); + util::StringView exportName = parser::SourceTextModuleRecord::DEFAULT_EXTERNAL_NAME; util::StringView localName; if (declNode->IsFunctionDeclaration() || declNode->IsClassDeclaration()) { const ir::Identifier *name = declNode->IsFunctionDeclaration() ? declNode->AsFunctionDeclaration()->Function()->Id() : declNode->AsClassDeclaration()->Definition()->Ident(); - localName = name == nullptr ? util::StringView("*default*") : name->Name(); + localName = name == nullptr ? parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME : name->Name(); } if (declNode->IsExpression()) { - localName = util::StringView("*default*"); + localName = parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; } + ASSERT(!localName.Empty()); - moduleRecord->AddLocalExportEntry(exportName, - localName, - declNode->Start()); + auto *entry = moduleRecord->NewEntry(exportName, localName); + if(!moduleRecord->AddLocalExportEntry(entry)) { + ThrowSyntaxError("Duplicate export name of '" + exportName.Mutf8() + "'", declNode->Start()); + } } void ParserImpl::AddExportLocalEntryItem(const ir::Statement *declNode) { ASSERT(declNode != nullptr); auto moduleRecord = GetSourceTextModuleRecord(); + ASSERT(moduleRecord != nullptr); if (declNode->IsVariableDeclaration()) { auto declarators = declNode->AsVariableDeclaration()->Declarators(); for (auto *decl : declarators) { std::vector bindings = util::Helpers::CollectBindingNames(decl->Id()); for (const auto *binding : bindings) { - moduleRecord->AddLocalExportEntry(binding->Name(), - binding->Name(), - binding->Start()); + auto *entry = moduleRecord->NewEntry( + binding->Name(), binding->Name()); + if(!moduleRecord->AddLocalExportEntry(entry)) { + ThrowSyntaxError("Duplicate export name of '" + binding->Name().Mutf8() + "'", binding->Start()); + } } } } @@ -2068,9 +2077,10 @@ void ParserImpl::AddExportLocalEntryItem(const ir::Statement *declNode) ThrowSyntaxError("A class or function declaration without the default modifier mush have a name.", declNode->Start()); } - moduleRecord->AddLocalExportEntry(name->Name(), - name->Name(), - name->Start()); + auto *entry = moduleRecord->NewEntry(name->Name(), name->Name()); + if(!moduleRecord->AddLocalExportEntry(entry)) { + ThrowSyntaxError("Duplicate export name of '" + name->Name().Mutf8() + "'", name->Start()); + } } } @@ -2089,20 +2099,19 @@ ir::ExportDefaultDeclaration *ParserImpl::ParseExportDefaultDeclaration(const le } if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_FUNCTION) { - declNode = ParseFunctionDeclaration(true, ParserStatus::NO_OPTS, false, true); + declNode = ParseFunctionDeclaration(true, ParserStatus::EXPORT_REACHED); } else if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_CLASS) { declNode = ParseClassDeclaration(false, std::move(decorators), false, false, true); } else if (lexer_->GetToken().IsAsyncModifier()) { lexer_->NextToken(); // eat `async` keyword - declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION, false, true); + declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION | ParserStatus::EXPORT_REACHED); } else if (Extension() == ScriptExtension::TS && lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_INTERFACE) { declNode = ParseTsInterfaceDeclaration(); } else { declNode = ParseExpression(); - Binder()->AddDecl(declNode->Start(), - util::StringView("*default*"), - binder::DeclModuleStatus::EXPORT); + Binder()->AddDecl(declNode->Start(), binder::DeclarationFlags::EXPORT, + parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME); eatSemicolon = true; } @@ -2235,21 +2244,22 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); } + VariableParsingFlags flag = VariableParsingFlags::EXPORTED; switch (lexer_->GetToken().Type()) { case lexer::TokenType::KEYW_VAR: { - decl = ParseVariableDeclaration(VariableParsingFlags::VAR, isDeclare, true); + decl = ParseVariableDeclaration(flag | VariableParsingFlags::VAR, isDeclare); break; } case lexer::TokenType::KEYW_CONST: { - decl = ParseVariableDeclaration(VariableParsingFlags::CONST, isDeclare, true); + decl = ParseVariableDeclaration(flag | VariableParsingFlags::CONST, isDeclare); break; } case lexer::TokenType::KEYW_LET: { - decl = ParseVariableDeclaration(VariableParsingFlags::LET, isDeclare, true); + decl = ParseVariableDeclaration(flag | VariableParsingFlags::LET, isDeclare); break; } case lexer::TokenType::KEYW_FUNCTION: { - decl = ParseFunctionDeclaration(false, ParserStatus::NO_OPTS, isDeclare, true); + decl = ParseFunctionDeclaration(false, ParserStatus::EXPORT_REACHED, isDeclare); break; } case lexer::TokenType::KEYW_CLASS: { @@ -2304,7 +2314,7 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: } lexer_->NextToken(); // eat `async` keyword - decl = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION, false, true); + decl = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION | ParserStatus::EXPORT_REACHED); } } @@ -2389,7 +2399,9 @@ void ParserImpl::ParseNameSpaceImport(ArenaVector *specifiers) specifier->SetRange({namespaceStart, lexer_->GetToken().End()}); specifiers->push_back(specifier); - Binder()->AddDecl(namespaceStart, local->Name(), binder::DeclModuleStatus::NONE); + auto *decl = Binder()->AddDecl(namespaceStart, binder::DeclarationFlags::NAMESPACE_IMPORT, + local->Name()); + decl->BindNode(specifier); lexer_->NextToken(); // eat local name } @@ -2446,7 +2458,7 @@ void ParserImpl::ParseNamedImportSpecifiers(ArenaVector *specifie specifier->SetRange({imported->Start(), local->End()}); specifiers->push_back(specifier); - Binder()->AddDecl(local->Start(), local->Name(), binder::DeclModuleStatus::IMPORT); + Binder()->AddDecl(local->Start(), binder::DeclarationFlags::IMPORT, local->Name()); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat comma @@ -2515,9 +2527,7 @@ ir::AstNode *ParserImpl::ParseImportDefaultSpecifier(ArenaVector specifier->SetRange(specifier->Local()->Range()); specifiers->push_back(specifier); - Binder()->AddDecl(local->Start(), local->Name(), binder::DeclModuleStatus::IMPORT); - - // lexer_->NextToken(); // eat specifier name + Binder()->AddDecl(local->Start(), binder::DeclarationFlags::IMPORT, local->Name()); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(); // eat comma diff --git a/es2panda/util/helpers.cpp b/es2panda/util/helpers.cpp index 2d2db346c5..84537cbe79 100644 --- a/es2panda/util/helpers.cpp +++ b/es2panda/util/helpers.cpp @@ -30,6 +30,7 @@ #include #include #include +#include namespace panda::es2panda::util { @@ -300,7 +301,7 @@ util::StringView Helpers::FunctionName(const ir::ScriptFunction *func) } if (func->Parent()->IsFunctionDeclaration()) { - return "default"; + return parser::SourceTextModuleRecord::DEFAULT_EXTERNAL_NAME; } const ir::AstNode *parent = func->Parent()->Parent(); @@ -362,7 +363,7 @@ util::StringView Helpers::FunctionName(const ir::ScriptFunction *func) break; } case ir::AstNodeType::EXPORT_DEFAULT_DECLARATION: { - return util::StringView("default"); + return parser::SourceTextModuleRecord::DEFAULT_EXTERNAL_NAME; } default: break; -- Gitee From 072207099b10fd86949d4e19bb56a9c449f12874 Mon Sep 17 00:00:00 2001 From: hufeng Date: Wed, 3 Aug 2022 16:02:36 +0800 Subject: [PATCH 3/4] code polish Signed-off-by: hufeng Change-Id: I4c04d42e30cf923a63e6b683ac020543d8a3fd91 --- es2panda/binder/binder.cpp | 6 +- es2panda/binder/binder.h | 2 +- es2panda/binder/declaration.h | 5 ++ es2panda/binder/scope.cpp | 2 +- es2panda/binder/scope.h | 34 +++++------ es2panda/compiler/base/hoisting.cpp | 24 ++++---- es2panda/compiler/core/emitter/emitter.h | 35 +---------- .../core/emitter/moduleRecordEmitter.cpp | 2 +- .../core/emitter/moduleRecordEmitter.h | 61 +++++++++++++++++++ es2panda/parser/module/module.cpp | 52 ++++++++-------- es2panda/parser/module/module.h | 7 ++- es2panda/parser/statementParser.cpp | 6 +- 12 files changed, 135 insertions(+), 101 deletions(-) create mode 100644 es2panda/compiler/core/emitter/moduleRecordEmitter.h diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index 909a4f54d3..1230b2173c 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -97,7 +97,7 @@ void Binder::IdentifierAnalysis() AddMandatoryParams(); } -void Binder::ValidateLocalExportDeclared(const ir::ExportNamedDeclaration *exportDecl) +void Binder::ValidateExportDecl(const ir::ExportNamedDeclaration *exportDecl) { if (exportDecl->Source() != nullptr || exportDecl->Decl() != nullptr) { return; @@ -109,7 +109,7 @@ void Binder::ValidateLocalExportDeclared(const ir::ExportNamedDeclaration *expor if (topScope_->FindLocal(localName) == nullptr) { ThrowUndeclaredExport(it->AsExportSpecifier()->Local()->Start(), localName); } - topScope_->AsModuleScope()->SetVariableAsExported(Allocator(), localName); + topScope_->AsModuleScope()->ConvertLocalVariableToModuleVariable(Allocator(), localName); } } @@ -477,7 +477,7 @@ void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) break; } case ir::AstNodeType::EXPORT_NAMED_DECLARATION: { - ValidateLocalExportDeclared(childNode->AsExportNamedDeclaration()); + ValidateExportDecl(childNode->AsExportNamedDeclaration()); ResolveReferences(childNode); break; diff --git a/es2panda/binder/binder.h b/es2panda/binder/binder.h index b0deb4fb0c..7205fe7d18 100644 --- a/es2panda/binder/binder.h +++ b/es2panda/binder/binder.h @@ -146,7 +146,7 @@ private: void LookupIdentReference(ir::Identifier *ident); void ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode); void ResolveReferences(const ir::AstNode *parent); - void ValidateLocalExportDeclared(const ir::ExportNamedDeclaration *exportDecl); + void ValidateExportDecl(const ir::ExportNamedDeclaration *exportDecl); parser::Program *program_ {}; FunctionScope *topScope_ {}; diff --git a/es2panda/binder/declaration.h b/es2panda/binder/declaration.h index ec2da81fd2..372d697569 100644 --- a/es2panda/binder/declaration.h +++ b/es2panda/binder/declaration.h @@ -82,6 +82,11 @@ public: return IsLetDecl() || IsConstDecl() || IsClassDecl(); } + DeclarationFlags Flags() const + { + return flags_; + } + void AddFlag(DeclarationFlags flag) { flags_ |= flag; diff --git a/es2panda/binder/scope.cpp b/es2panda/binder/scope.cpp index 391630c70c..9d222e2cd9 100644 --- a/es2panda/binder/scope.cpp +++ b/es2panda/binder/scope.cpp @@ -342,7 +342,7 @@ bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl // ModuleScope -void ModuleScope::SetVariableAsExported(ArenaAllocator *allocator, util::StringView localName) +void ModuleScope::ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName) { auto res = bindings_.find(localName); // Since the module's exported [localName] has been validated before, diff --git a/es2panda/binder/scope.h b/es2panda/binder/scope.h index bd038ca9f2..a1c71e0ff6 100644 --- a/es2panda/binder/scope.h +++ b/es2panda/binder/scope.h @@ -295,6 +295,8 @@ protected: explicit VariableScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent), lexicalVarNames_(allocator->Adapter()) {} + inline VariableFlags DeclFlagToVariableFlag(DeclarationFlags declFlag); + template bool AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); @@ -597,21 +599,28 @@ public: return ScopeType::MODULE; } - void SetVariableAsExported(ArenaAllocator *allocator, util::StringView localName); + void ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName); bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension) override; }; +inline VariableFlags VariableScope::DeclFlagToVariableFlag(DeclarationFlags declFlag) +{ + VariableFlags varFlag = VariableFlags::NONE; + if (declFlag & DeclarationFlags::EXPORT) { + varFlag |= VariableFlags::LOCAL_EXPORT; + } else if (declFlag & DeclarationFlags::IMPORT) { + varFlag |= VariableFlags::IMPORT; + } + return varFlag; +} + template bool VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { VariableFlags flags = VariableFlags::HOIST_VAR; - if (newDecl->HasFlag(DeclarationFlags::EXPORT)) { - flags |= VariableFlags::LOCAL_EXPORT; - } else if (newDecl->HasFlag(DeclarationFlags::IMPORT)) { - flags |= VariableFlags::IMPORT; - } + flags |= DeclFlagToVariableFlag(newDecl->Flags()); if (!currentVariable) { bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); @@ -640,11 +649,7 @@ bool VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVari [[maybe_unused]] ScriptExtension extension) { VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST; - if (newDecl->HasFlag(DeclarationFlags::EXPORT)) { - flags |= VariableFlags::LOCAL_EXPORT; - } else if (newDecl->HasFlag(DeclarationFlags::IMPORT)) { - flags |= VariableFlags::IMPORT; - } + flags |= DeclFlagToVariableFlag(newDecl->Flags()); if (!currentVariable) { bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); @@ -681,12 +686,7 @@ bool VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Var template bool VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { - VariableFlags flags = VariableFlags::NONE; - if (newDecl->HasFlag(DeclarationFlags::EXPORT)) { - flags |= VariableFlags::LOCAL_EXPORT; - } else if (newDecl->HasFlag(DeclarationFlags::IMPORT)) { - flags |= VariableFlags::IMPORT; - } + VariableFlags flags = DeclFlagToVariableFlag(newDecl->Flags()); if (currentVariable) { return false; diff --git a/es2panda/compiler/base/hoisting.cpp b/es2panda/compiler/base/hoisting.cpp index 1ec33b1323..89835637b4 100644 --- a/es2panda/compiler/base/hoisting.cpp +++ b/es2panda/compiler/base/hoisting.cpp @@ -23,6 +23,16 @@ namespace panda::es2panda::compiler { +static void StoreModuleVarOrLocalVar(PandaGen *pg, binder::ScopeFindResult &result, const binder::Decl *decl) +{ + if (decl->IsImportOrExportDecl()) { + ASSERT(pg->Scope()->IsModuleScope()); + pg->StoreModuleVariable(decl->Node(), decl->Name()); + } else { + pg->StoreAccToLexEnv(decl->Node(), result, true); + } +} + static void HoistVar(PandaGen *pg, binder::Variable *var, const binder::VarDecl *decl) { auto *scope = pg->Scope(); @@ -41,12 +51,7 @@ static void HoistVar(PandaGen *pg, binder::Variable *var, const binder::VarDecl binder::ScopeFindResult result(decl->Name(), scope, 0, var); pg->LoadConst(decl->Node(), Constant::JS_UNDEFINED); - if (decl->HasFlag(binder::DeclarationFlags::EXPORT)) { - ASSERT(scope->IsModuleScope()); - pg->StoreModuleVariable(decl->Node(), decl->Name()); - } else { - pg->StoreAccToLexEnv(decl->Node(), result, true); - } + StoreModuleVarOrLocalVar(pg, result, decl); } static void HoistFunction(PandaGen *pg, binder::Variable *var, const binder::FunctionDecl *decl) @@ -66,12 +71,7 @@ static void HoistFunction(PandaGen *pg, binder::Variable *var, const binder::Fun binder::ScopeFindResult result(decl->Name(), scope, 0, var); pg->DefineFunction(decl->Node(), scriptFunction, internalName); - if (decl->HasFlag(binder::DeclarationFlags::EXPORT)) { - ASSERT(scope->IsModuleScope()); - pg->StoreModuleVariable(decl->Node(), decl->Name()); - } else { - pg->StoreAccToLexEnv(decl->Node(), result, true); - } + StoreModuleVarOrLocalVar(pg, result, decl); } static void HoistNameSpaceImports(PandaGen *pg) diff --git a/es2panda/compiler/core/emitter/emitter.h b/es2panda/compiler/core/emitter/emitter.h index 27f22a0490..a19cabcb8c 100644 --- a/es2panda/compiler/core/emitter/emitter.h +++ b/es2panda/compiler/core/emitter/emitter.h @@ -17,10 +17,10 @@ #define ES2PANDA_COMPILER_IR_EMITTER_H #include +#include #include #include #include -#include #include #include @@ -93,39 +93,6 @@ private: size_t offset_ {0}; }; -class ModuleRecordEmitter { -public: - explicit ModuleRecordEmitter(parser::SourceTextModuleRecord *moduleRecord, int32_t bufferIdx) - : moduleRecord_(moduleRecord), bufferIdx_(bufferIdx) {} - ~ModuleRecordEmitter() = default; - NO_COPY_SEMANTIC(ModuleRecordEmitter); - NO_MOVE_SEMANTIC(ModuleRecordEmitter); - - int32_t Index() const - { - return bufferIdx_; - } - - auto &Buffer() - { - return buffer_; - } - - void Generate(); - -private: - void GenModuleRequests(); - void GenRegularImportEntries(); - void GenNamespaceImportEntries(); - void GenLocalExportEntries(); - void GenIndirectExportEntries(); - void GenStarExportEntries(); - - parser::SourceTextModuleRecord *moduleRecord_; - int32_t bufferIdx_ {}; - std::vector buffer_; -}; - class Emitter { public: explicit Emitter(const CompilerContext *context); diff --git a/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp b/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp index d3f6ffdd96..57ea1adf60 100644 --- a/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp +++ b/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "emitter.h" +#include "moduleRecordEmitter.h" namespace panda::es2panda::compiler { diff --git a/es2panda/compiler/core/emitter/moduleRecordEmitter.h b/es2panda/compiler/core/emitter/moduleRecordEmitter.h new file mode 100644 index 0000000000..78f859c4a7 --- /dev/null +++ b/es2panda/compiler/core/emitter/moduleRecordEmitter.h @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_IR_MODULERECORD_EMITTER_H +#define ES2PANDA_COMPILER_IR_MODULERECORD_EMITTER_H + +#include +#include + +#include + +namespace panda::es2panda::compiler { + +class ModuleRecordEmitter { +public: + explicit ModuleRecordEmitter(parser::SourceTextModuleRecord *moduleRecord, int32_t bufferIdx) + : moduleRecord_(moduleRecord), bufferIdx_(bufferIdx) {} + ~ModuleRecordEmitter() = default; + NO_COPY_SEMANTIC(ModuleRecordEmitter); + NO_MOVE_SEMANTIC(ModuleRecordEmitter); + + int32_t Index() const + { + return bufferIdx_; + } + + auto &Buffer() + { + return buffer_; + } + + void Generate(); + +private: + void GenModuleRequests(); + void GenRegularImportEntries(); + void GenNamespaceImportEntries(); + void GenLocalExportEntries(); + void GenIndirectExportEntries(); + void GenStarExportEntries(); + + parser::SourceTextModuleRecord *moduleRecord_; + int32_t bufferIdx_ {}; + std::vector buffer_; +}; + +} // namespace panda::es2panda::compiler + +#endif diff --git a/es2panda/parser/module/module.cpp b/es2panda/parser/module/module.cpp index 1565bf8535..4047e7bde9 100644 --- a/es2panda/parser/module/module.cpp +++ b/es2panda/parser/module/module.cpp @@ -41,7 +41,7 @@ namespace panda::es2panda::parser { // the implicit indirect exports should be insert into indirectExportsEntries // when add an ImportEntry. // e.g. export { x }; import { x } from 'test.js' - ConvertLocalExportsToIndirect(entry); + CheckImplicitIndirectExport(entry); } // import * as x from 'test.js'; @@ -68,10 +68,10 @@ namespace panda::es2panda::parser { // the implicit indirect exports should be insert into indirectExportsEntries // when add an ExportEntry. // e.g. import { x } from 'test.js'; export { x } - if (ConvertLocalExportsToIndirect(entry)) { + if (CheckImplicitIndirectExport(entry)) { return true; } - if (CheckDuplicateExports(entry->exportName_)) { + if (!HasDuplicateExport(entry->exportName_)) { localExportEntries_.insert(std::make_pair(entry->localName_, entry)); return true; } @@ -87,7 +87,7 @@ namespace panda::es2panda::parser { ASSERT(!entry->exportName_.Empty()); ASSERT(entry->localName_.Empty()); ASSERT(entry->moduleRequestIdx_ != -1); - if (CheckDuplicateExports(entry->exportName_)) { + if (!HasDuplicateExport(entry->exportName_)) { indirectExportEntries_.push_back(entry); return true; } @@ -104,42 +104,36 @@ namespace panda::es2panda::parser { starExportEntries_.push_back(entry); } - bool SourceTextModuleRecord::CheckDuplicateExports(util::StringView exportName) + bool SourceTextModuleRecord::HasDuplicateExport(util::StringView exportName) { for (auto const &entryUnit : localExportEntries_) { const SourceTextModuleRecord::ExportEntry *e = entryUnit.second; if (exportName == e->exportName_) { - return false; + return true; } } for (const auto *e : indirectExportEntries_) { if (exportName == e->exportName_) { - return false; + return true; } } - return true; + return false; } - bool SourceTextModuleRecord::ConvertLocalExportsToIndirect(SourceTextModuleRecord::ExportEntry *exportEntry) + bool SourceTextModuleRecord::CheckImplicitIndirectExport(SourceTextModuleRecord::ExportEntry *exportEntry) { ASSERT(!exportEntry->localName_.Empty()); - auto importEntry = regularImportEntries_.find(exportEntry->localName_); - if (importEntry != regularImportEntries_.end()) { - ASSERT(exportEntry->importName_.Empty()); - ASSERT(exportEntry->moduleRequestIdx_ == -1); - ASSERT(!importEntry->second->importName_.Empty()); - ASSERT(importEntry->second->moduleRequestIdx_ != -1); - exportEntry->importName_ = importEntry->second->importName_; - exportEntry->moduleRequestIdx_ = importEntry->second->moduleRequestIdx_; - exportEntry->localName_ = util::StringView(""); + auto regularImport = regularImportEntries_.find(exportEntry->localName_); + if (regularImport != regularImportEntries_.end()) { + ConvertLocalExportToIndirect(regularImport->second, exportEntry); return AddIndirectExportEntry(exportEntry); } return false; } - void SourceTextModuleRecord::ConvertLocalExportsToIndirect(SourceTextModuleRecord::ImportEntry *importEntry) + void SourceTextModuleRecord::CheckImplicitIndirectExport(SourceTextModuleRecord::ImportEntry *importEntry) { ASSERT(!importEntry->localName_.Empty()); auto range = localExportEntries_.equal_range(importEntry->localName_); @@ -150,15 +144,21 @@ namespace panda::es2panda::parser { for (auto it = range.first; it != range.second; ++it) { SourceTextModuleRecord::ExportEntry *exportEntry = it->second; - ASSERT(exportEntry->importName_.Empty()); - ASSERT(exportEntry->moduleRequestIdx_ == -1); - ASSERT(!importEntry->importName_.Empty()); - ASSERT(importEntry->moduleRequestIdx_ != -1); - exportEntry->importName_ = importEntry->importName_; - exportEntry->moduleRequestIdx_ = importEntry->moduleRequestIdx_; - exportEntry->localName_ = util::StringView(""); + ConvertLocalExportToIndirect(importEntry, exportEntry); indirectExportEntries_.push_back(exportEntry); } localExportEntries_.erase(range.first, range.second); } + + void SourceTextModuleRecord::ConvertLocalExportToIndirect(SourceTextModuleRecord::ImportEntry *importEntry, + SourceTextModuleRecord::ExportEntry *exportEntry) + { + ASSERT(exportEntry->importName_.Empty()); + ASSERT(exportEntry->moduleRequestIdx_ == -1); + ASSERT(!importEntry->importName_.Empty()); + ASSERT(importEntry->moduleRequestIdx_ != -1); + exportEntry->importName_ = importEntry->importName_; + exportEntry->moduleRequestIdx_ = importEntry->moduleRequestIdx_; + exportEntry->localName_ = util::StringView(""); + } } // namespace panda::es2panda::parser diff --git a/es2panda/parser/module/module.h b/es2panda/parser/module/module.h index fa301218b2..91433c4df2 100644 --- a/es2panda/parser/module/module.h +++ b/es2panda/parser/module/module.h @@ -82,8 +82,8 @@ class SourceTextModuleRecord { bool AddIndirectExportEntry(ExportEntry *entry); void AddStarExportEntry(ExportEntry *entry); - bool ConvertLocalExportsToIndirect(ExportEntry *exportEntry); - void ConvertLocalExportsToIndirect(ImportEntry *importEntry); + bool CheckImplicitIndirectExport(ExportEntry *exportEntry); + void CheckImplicitIndirectExport(ImportEntry *importEntry); using ModuleRequestList = ArenaVector; using ModuleRequestMap = ArenaMap; @@ -127,7 +127,8 @@ class SourceTextModuleRecord { static constexpr std::string_view ANONY_NAMESPACE_NAME = "=ens"; private: - bool CheckDuplicateExports(util::StringView exportName); + bool HasDuplicateExport(util::StringView exportName); + void ConvertLocalExportToIndirect(ImportEntry *importEntry, ExportEntry *exportEntry); ArenaAllocator *allocator_; ModuleRequestMap moduleRequestsMap_; diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index 6d08ae98aa..1aba4b0a09 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -521,9 +521,9 @@ ir::ClassDeclaration *ParserImpl::ParseClassDeclaration(bool idRequired, ArenaVe lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ir::ClassDefinition *classDefinition = ParseClassDefinition(true, idRequired, isDeclare, isAbstract); - auto location = classDefinition->Ident() == nullptr ? startLoc : classDefinition->Ident()->Start(); - auto className = classDefinition->Ident() == nullptr ? parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME : - classDefinition->Ident()->Name(); + auto location = classDefinition->Ident() ? classDefinition->Ident()->Start() : startLoc; + auto className = classDefinition->Ident() ? classDefinition->Ident()->Name() : + parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; binder::DeclarationFlags flag = isExported ? binder::DeclarationFlags::EXPORT : binder::DeclarationFlags::NONE; auto *decl = Binder()->AddDecl(location, flag, className); -- Gitee From 0263702ee75e1e5ef4c27b67e22cc2d6a1ccea67 Mon Sep 17 00:00:00 2001 From: hufeng Date: Thu, 4 Aug 2022 14:39:15 +0800 Subject: [PATCH 4/4] code polish stage_2 Signed-off-by: hufeng Change-Id: I3fad20b92f7ebb1f8f0a6d935ce1fd9f6be540c6 --- es2panda/BUILD.gn | 2 +- es2panda/binder/binder.cpp | 9 +- es2panda/binder/scope.h | 4 +- es2panda/compiler/base/hoisting.cpp | 2 +- es2panda/compiler/base/lexenv.cpp | 2 +- es2panda/compiler/base/lreference.cpp | 7 + es2panda/compiler/core/compileQueue.cpp | 6 + es2panda/compiler/core/emitter/emitter.cpp | 2 - es2panda/compiler/core/emitter/emitter.h | 2 - .../core/emitter/moduleRecordEmitter.cpp | 2 - .../core/emitter/moduleRecordEmitter.h | 4 +- es2panda/compiler/core/pandagen.cpp | 6 +- es2panda/ir/base/classDefinition.cpp | 13 ++ es2panda/ir/base/classDefinition.h | 13 +- es2panda/ir/base/scriptFunction.cpp | 13 ++ es2panda/ir/base/scriptFunction.h | 10 +- .../ir/module/exportDefaultDeclaration.cpp | 6 +- es2panda/ir/statements/classDeclaration.cpp | 16 +- es2panda/parser/module/module.h | 145 ------------------ ...{module.cpp => sourceTextModuleRecord.cpp} | 23 ++- .../parser/module/sourceTextModuleRecord.h | 139 +++++++++++++++++ es2panda/parser/parserImpl.h | 2 +- es2panda/parser/program/program.h | 2 +- es2panda/parser/statementParser.cpp | 35 ++--- es2panda/util/helpers.cpp | 2 +- 25 files changed, 251 insertions(+), 216 deletions(-) delete mode 100644 es2panda/parser/module/module.h rename es2panda/parser/module/{module.cpp => sourceTextModuleRecord.cpp} (94%) create mode 100644 es2panda/parser/module/sourceTextModuleRecord.h diff --git a/es2panda/BUILD.gn b/es2panda/BUILD.gn index 38e1f79d15..748ea2045c 100644 --- a/es2panda/BUILD.gn +++ b/es2panda/BUILD.gn @@ -186,7 +186,7 @@ es2panda_src = [ "lexer/token/token.cpp", "parser/context/parserContext.cpp", "parser/expressionParser.cpp", - "parser/module/module.cpp", + "parser/module/sourceTextModuleRecord.cpp", "parser/parserImpl.cpp", "parser/program/program.cpp", "parser/statementParser.cpp", diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index 1230b2173c..905a417b91 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -282,13 +282,8 @@ void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl) void Binder::BuildClassDefinition(ir::ClassDefinition *classDef) { if (classDef->Parent()->IsClassDeclaration()) { - util::StringView className; - if (classDef->Ident()) { - className = classDef->Ident()->Name(); - } else { - ASSERT(scope_->IsModuleScope()); - className = parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; - } + util::StringView className = classDef->GetName(); + ASSERT(!className.Empty()); ScopeFindResult res = scope_->Find(className); ASSERT(res.variable && res.variable->Declaration()->IsClassDecl()); diff --git a/es2panda/binder/scope.h b/es2panda/binder/scope.h index a1c71e0ff6..a6046c098a 100644 --- a/es2panda/binder/scope.h +++ b/es2panda/binder/scope.h @@ -609,9 +609,9 @@ inline VariableFlags VariableScope::DeclFlagToVariableFlag(DeclarationFlags decl { VariableFlags varFlag = VariableFlags::NONE; if (declFlag & DeclarationFlags::EXPORT) { - varFlag |= VariableFlags::LOCAL_EXPORT; + varFlag = VariableFlags::LOCAL_EXPORT; } else if (declFlag & DeclarationFlags::IMPORT) { - varFlag |= VariableFlags::IMPORT; + varFlag = VariableFlags::IMPORT; } return varFlag; } diff --git a/es2panda/compiler/base/hoisting.cpp b/es2panda/compiler/base/hoisting.cpp index 89835637b4..e8b61fc97d 100644 --- a/es2panda/compiler/base/hoisting.cpp +++ b/es2panda/compiler/base/hoisting.cpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include namespace panda::es2panda::compiler { diff --git a/es2panda/compiler/base/lexenv.cpp b/es2panda/compiler/base/lexenv.cpp index 3db467f021..bd75ca475a 100644 --- a/es2panda/compiler/base/lexenv.cpp +++ b/es2panda/compiler/base/lexenv.cpp @@ -45,7 +45,7 @@ static void ExpandLoadLexVar(PandaGen *pg, const ir::AstNode *node, const binder pg->LoadLexicalVar(node, result.lexLevel, result.variable->AsLocalVariable()->LexIdx()); const auto *decl = result.variable->Declaration(); if (decl->IsLetOrConstOrClassDecl()) { - pg->ThrowUndefinedIfHole(node, result.variable->Name()); + pg->ThrowUndefinedIfHole(node, result.variable->Name()); } } diff --git a/es2panda/compiler/base/lreference.cpp b/es2panda/compiler/base/lreference.cpp index 6fd21e14ee..53587e65b4 100644 --- a/es2panda/compiler/base/lreference.cpp +++ b/es2panda/compiler/base/lreference.cpp @@ -123,6 +123,13 @@ LReference LReference::CreateLRef(PandaGen *pg, const ir::AstNode *node, bool is case ir::AstNodeType::REST_ELEMENT: { return LReference::CreateLRef(pg, node->AsRestElement()->Argument(), true); } + case ir::AstNodeType::EXPORT_DEFAULT_DECLARATION: { + // export default [anonymous class decl] + util::StringView name = parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; + binder::ScopeFindResult res = pg->Scope()->Find(name); + + return {node, pg, isDeclaration, ReferenceKind::VAR_OR_GLOBAL, res}; + } default: { UNREACHABLE(); } diff --git a/es2panda/compiler/core/compileQueue.cpp b/es2panda/compiler/core/compileQueue.cpp index 3bc6866a0e..67dbd851a2 100644 --- a/es2panda/compiler/core/compileQueue.cpp +++ b/es2panda/compiler/core/compileQueue.cpp @@ -167,6 +167,12 @@ void CompileQueue::Wait() { std::unique_lock lock(m_); jobsFinished_.wait(lock, [this]() { return activeWorkers_ == 0 && jobsCount_ == 0; }); + for (auto it = jobs_.begin(); it != jobs_.end(); it++) { + if (*it != nullptr) { + delete *it; + *it =nullptr; + } + } jobs_.clear(); if (!errors_.empty()) { diff --git a/es2panda/compiler/core/emitter/emitter.cpp b/es2panda/compiler/core/emitter/emitter.cpp index 1045d77aec..ecec4eead8 100644 --- a/es2panda/compiler/core/emitter/emitter.cpp +++ b/es2panda/compiler/core/emitter/emitter.cpp @@ -37,7 +37,6 @@ #include namespace panda::es2panda::compiler { - constexpr const auto LANG_EXT = panda::pandasm::extensions::Language::ECMASCRIPT; FunctionEmitter::FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg) @@ -457,5 +456,4 @@ panda::pandasm::Program *Emitter::Finalize(bool dumpDebugInfo) prog_ = nullptr; return prog; } - } // namespace panda::es2panda::compiler diff --git a/es2panda/compiler/core/emitter/emitter.h b/es2panda/compiler/core/emitter/emitter.h index a19cabcb8c..9e3d9f934b 100644 --- a/es2panda/compiler/core/emitter/emitter.h +++ b/es2panda/compiler/core/emitter/emitter.h @@ -45,7 +45,6 @@ class Scope; } // namespace panda::es2panda::binder namespace panda::es2panda::compiler { - class PandaGen; class LiteralBuffer; class DebugInfo; @@ -111,7 +110,6 @@ private: std::mutex m_; panda::pandasm::Program *prog_; }; - } // namespace panda::es2panda::compiler #endif diff --git a/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp b/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp index 57ea1adf60..cd635669ff 100644 --- a/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp +++ b/es2panda/compiler/core/emitter/moduleRecordEmitter.cpp @@ -16,7 +16,6 @@ #include "moduleRecordEmitter.h" namespace panda::es2panda::compiler { - void ModuleRecordEmitter::GenModuleRequests() { ASSERT(moduleRecord_ != nullptr); @@ -136,5 +135,4 @@ void ModuleRecordEmitter::Generate() GenIndirectExportEntries(); GenStarExportEntries(); } - } // namespace panda::es2panda::compiler diff --git a/es2panda/compiler/core/emitter/moduleRecordEmitter.h b/es2panda/compiler/core/emitter/moduleRecordEmitter.h index 78f859c4a7..7aadbd1ae5 100644 --- a/es2panda/compiler/core/emitter/moduleRecordEmitter.h +++ b/es2panda/compiler/core/emitter/moduleRecordEmitter.h @@ -17,12 +17,11 @@ #define ES2PANDA_COMPILER_IR_MODULERECORD_EMITTER_H #include -#include +#include #include namespace panda::es2panda::compiler { - class ModuleRecordEmitter { public: explicit ModuleRecordEmitter(parser::SourceTextModuleRecord *moduleRecord, int32_t bufferIdx) @@ -55,7 +54,6 @@ private: int32_t bufferIdx_ {}; std::vector buffer_; }; - } // namespace panda::es2panda::compiler #endif diff --git a/es2panda/compiler/core/pandagen.cpp b/es2panda/compiler/core/pandagen.cpp index 4a268c7068..89b3f7e07e 100644 --- a/es2panda/compiler/core/pandagen.cpp +++ b/es2panda/compiler/core/pandagen.cpp @@ -232,8 +232,9 @@ void PandaGen::LoadVar(const ir::Identifier *node, const binder::ScopeFindResult if (var->IsModuleVariable()) { LoadModuleVariable(node, var->Name(), var->HasFlag(binder::VariableFlags::LOCAL_EXPORT)); - if (var->Declaration()->IsLetOrConstOrClassDecl()) + if (var->Declaration()->IsLetOrConstOrClassDecl()) { ThrowUndefinedIfHole(node, var->Name()); + } return; } @@ -267,7 +268,8 @@ void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult & return; } - if (!isDeclaration && var->Declaration()->IsLetDecl()) { + if (!isDeclaration && + (var->Declaration()->IsLetDecl() || var->Declaration()->IsClassDecl())) { RegScope rs(this); VReg valueReg = AllocReg(); StoreAccumulator(node, valueReg); diff --git a/es2panda/ir/base/classDefinition.cpp b/es2panda/ir/base/classDefinition.cpp index 260910e252..03507d5551 100644 --- a/es2panda/ir/base/classDefinition.cpp +++ b/es2panda/ir/base/classDefinition.cpp @@ -45,6 +45,19 @@ const FunctionExpression *ClassDefinition::Ctor() const return ctor_->Value(); } +util::StringView ClassDefinition::GetName() const +{ + if (ident_) { + return ident_->Name(); + } + + if (exportDefault_) { + return parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; + } + + return ""; +} + void ClassDefinition::Iterate(const NodeTraverser &cb) const { if (ident_) { diff --git a/es2panda/ir/base/classDefinition.h b/es2panda/ir/base/classDefinition.h index 32a1e3096c..6f02a09a70 100644 --- a/es2panda/ir/base/classDefinition.h +++ b/es2panda/ir/base/classDefinition.h @@ -16,8 +16,8 @@ #ifndef ES2PANDA_PARSER_INCLUDE_AST_CLASS_DEFINITION_H #define ES2PANDA_PARSER_INCLUDE_AST_CLASS_DEFINITION_H -#include #include +#include #include namespace panda::es2panda::compiler { @@ -61,7 +61,8 @@ public: body_(std::move(body)), indexSignatures_(std::move(indexSignatures)), declare_(declare), - abstract_(abstract) + abstract_(abstract), + exportDefault_(false) { } @@ -95,6 +96,11 @@ public: return abstract_; } + void SetAsExportDefault() + { + exportDefault_ = true; + } + ArenaVector &Body() { return body_; @@ -113,6 +119,8 @@ public: const FunctionExpression *Ctor() const; + util::StringView GetName() const; + void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; @@ -135,6 +143,7 @@ private: ArenaVector indexSignatures_; bool declare_; bool abstract_; + bool exportDefault_; }; } // namespace panda::es2panda::ir diff --git a/es2panda/ir/base/scriptFunction.cpp b/es2panda/ir/base/scriptFunction.cpp index d4d0678348..5a5e2035b2 100644 --- a/es2panda/ir/base/scriptFunction.cpp +++ b/es2panda/ir/base/scriptFunction.cpp @@ -40,6 +40,19 @@ size_t ScriptFunction::FormalParamsLength() const return length; } +util::StringView ScriptFunction::GetName() const +{ + if (id_) { + return id_->Name(); + } + + if (exportDefault_) { + return parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; + } + + return ""; +} + void ScriptFunction::Iterate(const NodeTraverser &cb) const { if (id_) { diff --git a/es2panda/ir/base/scriptFunction.h b/es2panda/ir/base/scriptFunction.h index b0b1e9403e..0353c259c3 100644 --- a/es2panda/ir/base/scriptFunction.h +++ b/es2panda/ir/base/scriptFunction.h @@ -49,7 +49,8 @@ public: body_(body), returnTypeAnnotation_(returnTypeAnnotation), flags_(flags), - declare_(declare) + declare_(declare), + exportDefault_(false) { } @@ -133,12 +134,18 @@ public: id_ = id; } + void SetAsExportDefault() + { + exportDefault_ = true; + } + void AddFlag(ir::ScriptFunctionFlags flags) { flags_ |= flags; } size_t FormalParamsLength() const; + util::StringView GetName() const; binder::FunctionScope *Scope() const { @@ -159,6 +166,7 @@ private: Expression *returnTypeAnnotation_; ir::ScriptFunctionFlags flags_; bool declare_; + bool exportDefault_; }; } // namespace panda::es2panda::ir diff --git a/es2panda/ir/module/exportDefaultDeclaration.cpp b/es2panda/ir/module/exportDefaultDeclaration.cpp index e2208de1fe..948b0d54e1 100644 --- a/es2panda/ir/module/exportDefaultDeclaration.cpp +++ b/es2panda/ir/module/exportDefaultDeclaration.cpp @@ -34,9 +34,9 @@ void ExportDefaultDeclaration::Dump(ir::AstDumper *dumper) const void ExportDefaultDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const { decl_->Compile(pg); - if (!decl_->IsFunctionDeclaration() && !decl_->IsClassDeclaration()) { - // export default without [Function Declaration] & [Class Declaration] - // is [ExportAssignment]. e.g. export default 42 (42 be exported as [default]) + if (decl_->IsExpression()) { + // export default [AssignmentExpression] + // e.g. export default 42 (42 be exported as [default]) pg->StoreModuleVariable(this, parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME); } } diff --git a/es2panda/ir/statements/classDeclaration.cpp b/es2panda/ir/statements/classDeclaration.cpp index ed3b591447..3c3893e44a 100644 --- a/es2panda/ir/statements/classDeclaration.cpp +++ b/es2panda/ir/statements/classDeclaration.cpp @@ -41,15 +41,13 @@ void ClassDeclaration::Dump(ir::AstDumper *dumper) const void ClassDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - if (def_->Ident()) { - auto lref = compiler::LReference::CreateLRef(pg, def_->Ident(), true); - def_->Compile(pg); - lref.SetValue(); - } else { - ASSERT(this->Parent()->IsExportDefaultDeclaration() && pg->Scope()->IsModuleScope()); - def_->Compile(pg); - pg->StoreModuleVariable(def_, parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME); - } + // [ClassDeclaration] without [Identifier] must have parent node + // of [ExportDefaultDeclaration] during compiling phase. So we use + // the parent node to create a lreference with boundName of [*default*]. + const auto *node = def_->Ident() ? def_->Ident() : this->Parent(); + auto lref = compiler::LReference::CreateLRef(pg, node, true); + def_->Compile(pg); + lref.SetValue(); } checker::Type *ClassDeclaration::Check([[maybe_unused]] checker::Checker *checker) const diff --git a/es2panda/parser/module/module.h b/es2panda/parser/module/module.h deleted file mode 100644 index 91433c4df2..0000000000 --- a/es2panda/parser/module/module.h +++ /dev/null @@ -1,145 +0,0 @@ -/** - * Copyright (c) 2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ES2PANDA_PARSER_CORE_MODULE_H -#define ES2PANDA_PARSER_CORE_MODULE_H - -#include - -namespace panda::es2panda::binder { -class ModuleScope; -} // namespace panda::es2panda::binder - -namespace panda::es2panda::parser { - -class SourceTextModuleRecord { - public: - explicit SourceTextModuleRecord(ArenaAllocator *allocator) - : allocator_(allocator), - moduleRequestsMap_(allocator_->Adapter()), - moduleRequests_(allocator_->Adapter()), - localExportEntries_(allocator_->Adapter()), - regularImportEntries_(allocator_->Adapter()), - namespaceImportEntries_(allocator_->Adapter()), - starExportEntries_(allocator_->Adapter()), - indirectExportEntries_(allocator_->Adapter()) - { - } - - ~SourceTextModuleRecord() = default; - NO_COPY_SEMANTIC(SourceTextModuleRecord); - NO_MOVE_SEMANTIC(SourceTextModuleRecord); - - struct ImportEntry { - int moduleRequestIdx_; - util::StringView localName_; - util::StringView importName_; - - ImportEntry(const util::StringView localName, const util::StringView importName, int moduleRequestIdx) - : moduleRequestIdx_(moduleRequestIdx), localName_(localName), importName_(importName) {} - ImportEntry(const util::StringView localName, int moduleRequestIdx) - : moduleRequestIdx_(moduleRequestIdx), localName_(localName) {} - }; - - struct ExportEntry { - int moduleRequestIdx_; - util::StringView exportName_; - util::StringView localName_; - util::StringView importName_; - - ExportEntry(int moduleRequest) : moduleRequestIdx_(moduleRequest) {} - ExportEntry(const util::StringView exportName, const util::StringView localName) - : moduleRequestIdx_(-1), exportName_(exportName), localName_(localName) {} - ExportEntry(const util::StringView exportName, const util::StringView importName, int moduleRequest) - : moduleRequestIdx_(moduleRequest), exportName_(exportName) - { - importName_ = importName; - } - }; - - template - T *NewEntry(Args &&... args) - { - return allocator_->New(std::forward(args)...); - } - - int AddModuleRequest(const util::StringView source); - void AddImportEntry(ImportEntry *entry); - void AddStarImportEntry(ImportEntry *entry); - bool AddLocalExportEntry(ExportEntry *entry); - bool AddIndirectExportEntry(ExportEntry *entry); - void AddStarExportEntry(ExportEntry *entry); - - bool CheckImplicitIndirectExport(ExportEntry *exportEntry); - void CheckImplicitIndirectExport(ImportEntry *importEntry); - - using ModuleRequestList = ArenaVector; - using ModuleRequestMap = ArenaMap; - using LocalExportEntryMap = ArenaMultiMap; - using RegularImportEntryMap = ArenaMap; - using NamespaceImportEntryList = ArenaVector; - using SpecialExportEntryList = ArenaVector; - - const ArenaVector &GetModuleRequests() const - { - return moduleRequests_; - } - - const LocalExportEntryMap &GetLocalExportEntries() const - { - return localExportEntries_; - } - - const RegularImportEntryMap &GetRegularImportEntries() const - { - return regularImportEntries_; - } - - const NamespaceImportEntryList &GetNamespaceImportEntries() const - { - return namespaceImportEntries_; - } - - const SpecialExportEntryList &GetStarExportEntries() const - { - return starExportEntries_; - } - - const SpecialExportEntryList &GetIndirectExportEntries() const - { - return indirectExportEntries_; - } - - static constexpr std::string_view DEFAULT_LOCAL_NAME= "*default*"; - static constexpr std::string_view DEFAULT_EXTERNAL_NAME = "default"; - static constexpr std::string_view ANONY_NAMESPACE_NAME = "=ens"; - - private: - bool HasDuplicateExport(util::StringView exportName); - void ConvertLocalExportToIndirect(ImportEntry *importEntry, ExportEntry *exportEntry); - - ArenaAllocator *allocator_; - ModuleRequestMap moduleRequestsMap_; - ModuleRequestList moduleRequests_; - LocalExportEntryMap localExportEntries_; - RegularImportEntryMap regularImportEntries_; - NamespaceImportEntryList namespaceImportEntries_; - SpecialExportEntryList starExportEntries_; - SpecialExportEntryList indirectExportEntries_; -}; - -} // namespace panda::es2panda::parser - -#endif \ No newline at end of file diff --git a/es2panda/parser/module/module.cpp b/es2panda/parser/module/sourceTextModuleRecord.cpp similarity index 94% rename from es2panda/parser/module/module.cpp rename to es2panda/parser/module/sourceTextModuleRecord.cpp index 4047e7bde9..6a25328bcc 100644 --- a/es2panda/parser/module/module.cpp +++ b/es2panda/parser/module/sourceTextModuleRecord.cpp @@ -13,10 +13,9 @@ * limitations under the License. */ -#include "module.h" +#include "sourceTextModuleRecord.h" namespace panda::es2panda::parser { - int SourceTextModuleRecord::AddModuleRequest(const util::StringView source) { ASSERT(!source.Empty()); @@ -28,9 +27,9 @@ namespace panda::es2panda::parser { return insertedRes.first->second; } - // import x from 'test.js'; - // import {x} from 'test.js'; - // import {x as y} from 'test.js'; + // import x from 'test.js' + // import {x} from 'test.js' + // import {x as y} from 'test.js' // import defaultExport from 'test.js' void SourceTextModuleRecord::AddImportEntry(SourceTextModuleRecord::ImportEntry *entry) { @@ -44,7 +43,7 @@ namespace panda::es2panda::parser { CheckImplicitIndirectExport(entry); } - // import * as x from 'test.js'; + // import * as x from 'test.js' void SourceTextModuleRecord::AddStarImportEntry(SourceTextModuleRecord::ImportEntry *entry) { ASSERT(!entry->localName_.Empty()); @@ -53,8 +52,8 @@ namespace panda::es2panda::parser { namespaceImportEntries_.push_back(entry); } - // export {x}; - // export {x as y}; + // export {x} + // export {x as y} // export VariableStatement // export Declaration // export default ... @@ -78,9 +77,9 @@ namespace panda::es2panda::parser { return false; } - // export {x} from 'test.js'; - // export {x as y} from 'test.js'; - // import { x } from 'test.js'; export { x }; + // export {x} from 'test.js' + // export {x as y} from 'test.js' + // import { x } from 'test.js'; export { x } bool SourceTextModuleRecord::AddIndirectExportEntry(SourceTextModuleRecord::ExportEntry *entry) { ASSERT(!entry->importName_.Empty()); @@ -94,7 +93,7 @@ namespace panda::es2panda::parser { return false; } - // export * from 'test.js'; + // export * from 'test.js' void SourceTextModuleRecord::AddStarExportEntry(SourceTextModuleRecord::ExportEntry *entry) { ASSERT(entry->importName_.Empty()); diff --git a/es2panda/parser/module/sourceTextModuleRecord.h b/es2panda/parser/module/sourceTextModuleRecord.h new file mode 100644 index 0000000000..f4a52bf09d --- /dev/null +++ b/es2panda/parser/module/sourceTextModuleRecord.h @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_PARSER_CORE_MODULERECORD_H +#define ES2PANDA_PARSER_CORE_MODULERECORD_H + +#include + +namespace panda::es2panda::parser { +class SourceTextModuleRecord { +public: + explicit SourceTextModuleRecord(ArenaAllocator *allocator) + : allocator_(allocator), + moduleRequestsMap_(allocator_->Adapter()), + moduleRequests_(allocator_->Adapter()), + localExportEntries_(allocator_->Adapter()), + regularImportEntries_(allocator_->Adapter()), + namespaceImportEntries_(allocator_->Adapter()), + starExportEntries_(allocator_->Adapter()), + indirectExportEntries_(allocator_->Adapter()) + { + } + + ~SourceTextModuleRecord() = default; + NO_COPY_SEMANTIC(SourceTextModuleRecord); + NO_MOVE_SEMANTIC(SourceTextModuleRecord); + + struct ImportEntry { + int moduleRequestIdx_; + util::StringView localName_; + util::StringView importName_; + + ImportEntry(const util::StringView localName, const util::StringView importName, int moduleRequestIdx) + : moduleRequestIdx_(moduleRequestIdx), localName_(localName), importName_(importName) {} + ImportEntry(const util::StringView localName, int moduleRequestIdx) + : moduleRequestIdx_(moduleRequestIdx), localName_(localName) {} + }; + + struct ExportEntry { + int moduleRequestIdx_; + util::StringView exportName_; + util::StringView localName_; + util::StringView importName_; + + explicit ExportEntry(int moduleRequest) : moduleRequestIdx_(moduleRequest) {} + ExportEntry(const util::StringView exportName, const util::StringView localName) + : moduleRequestIdx_(-1), exportName_(exportName), localName_(localName) {} + ExportEntry(const util::StringView exportName, const util::StringView importName, int moduleRequest) + : moduleRequestIdx_(moduleRequest), exportName_(exportName) + { + importName_ = importName; + } + }; + + template + T *NewEntry(Args &&... args) + { + return allocator_->New(std::forward(args)...); + } + + int AddModuleRequest(const util::StringView source); + void AddImportEntry(ImportEntry *entry); + void AddStarImportEntry(ImportEntry *entry); + bool AddLocalExportEntry(ExportEntry *entry); + bool AddIndirectExportEntry(ExportEntry *entry); + void AddStarExportEntry(ExportEntry *entry); + + bool CheckImplicitIndirectExport(ExportEntry *exportEntry); + void CheckImplicitIndirectExport(ImportEntry *importEntry); + + using ModuleRequestList = ArenaVector; + using ModuleRequestMap = ArenaMap; + using LocalExportEntryMap = ArenaMultiMap; + using RegularImportEntryMap = ArenaMap; + using NamespaceImportEntryList = ArenaVector; + using SpecialExportEntryList = ArenaVector; + + const ArenaVector &GetModuleRequests() const + { + return moduleRequests_; + } + + const LocalExportEntryMap &GetLocalExportEntries() const + { + return localExportEntries_; + } + + const RegularImportEntryMap &GetRegularImportEntries() const + { + return regularImportEntries_; + } + + const NamespaceImportEntryList &GetNamespaceImportEntries() const + { + return namespaceImportEntries_; + } + + const SpecialExportEntryList &GetStarExportEntries() const + { + return starExportEntries_; + } + + const SpecialExportEntryList &GetIndirectExportEntries() const + { + return indirectExportEntries_; + } + + static constexpr std::string_view DEFAULT_LOCAL_NAME = "*default*"; + static constexpr std::string_view DEFAULT_EXTERNAL_NAME = "default"; + static constexpr std::string_view ANONY_NAMESPACE_NAME = "=ens"; + +private: + bool HasDuplicateExport(util::StringView exportName); + void ConvertLocalExportToIndirect(ImportEntry *importEntry, ExportEntry *exportEntry); + + ArenaAllocator *allocator_; + ModuleRequestMap moduleRequestsMap_; + ModuleRequestList moduleRequests_; + LocalExportEntryMap localExportEntries_; + RegularImportEntryMap regularImportEntries_; + NamespaceImportEntryList namespaceImportEntries_; + SpecialExportEntryList starExportEntries_; + SpecialExportEntryList indirectExportEntries_; +}; +} // namespace panda::es2panda::parser + +#endif \ No newline at end of file diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index 3381cd021c..c07300b81b 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/es2panda/parser/program/program.h b/es2panda/parser/program/program.h index 65db646333..33b750ed2d 100644 --- a/es2panda/parser/program/program.h +++ b/es2panda/parser/program/program.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include "es2panda.h" diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index 1aba4b0a09..4118364e21 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -520,10 +520,13 @@ ir::ClassDeclaration *ParserImpl::ParseClassDeclaration(bool idRequired, ArenaVe { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ir::ClassDefinition *classDefinition = ParseClassDefinition(true, idRequired, isDeclare, isAbstract); + if (isExported && !idRequired) { + classDefinition->SetAsExportDefault(); + } auto location = classDefinition->Ident() ? classDefinition->Ident()->Start() : startLoc; - auto className = classDefinition->Ident() ? classDefinition->Ident()->Name() : - parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; + auto className = classDefinition->GetName(); + ASSERT(!className.Empty()); binder::DeclarationFlags flag = isExported ? binder::DeclarationFlags::EXPORT : binder::DeclarationFlags::NONE; auto *decl = Binder()->AddDecl(location, flag, className); @@ -982,6 +985,7 @@ ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymou if (canBeAnonymous) { ir::ScriptFunction *func = ParseFunction(newStatus, isDeclare); func->SetStart(startLoc); + func->SetAsExportDefault(); auto *funcDecl = AllocNode(func); funcDecl->SetRange(func->Range()); @@ -1924,7 +1928,7 @@ void ParserImpl::AddImportEntryItem(const ir::StringLiteral *source, const Arena } for (auto *it : *specifiers) { - switch(it->Type()) { + switch (it->Type()) { case ir::AstNodeType::IMPORT_DEFAULT_SPECIFIER: { auto localName = it->AsImportDefaultSpecifier()->Local()->Name(); auto importName = parser::SourceTextModuleRecord::DEFAULT_EXTERNAL_NAME; @@ -1980,7 +1984,7 @@ void ParserImpl::AddExportNamedEntryItem(const ArenaVectorExported()->Name(); auto localName = exportSpecifier->Local()->Name(); auto *entry = moduleRecord->NewEntry(exportName, localName); - if(!moduleRecord->AddLocalExportEntry(entry)) { + if (!moduleRecord->AddLocalExportEntry(entry)) { ThrowSyntaxError("Duplicate export name of '" + exportName.Mutf8() + "'", exportSpecifier->Start()); } @@ -2013,7 +2017,7 @@ void ParserImpl::AddExportStarEntryItem(const lexer::SourcePosition &startLoc, c auto *exportEntry = moduleRecord->NewEntry( exported->Name(), namespaceExportInternalName); moduleRecord->AddStarImportEntry(importEntry); - if(!moduleRecord->AddLocalExportEntry(exportEntry)) { + if (!moduleRecord->AddLocalExportEntry(exportEntry)) { ThrowSyntaxError("Duplicate export name of '" + exported->Name().Mutf8() + "'", exported->Start()); } return; @@ -2033,20 +2037,15 @@ void ParserImpl::AddExportDefaultEntryItem(const ir::AstNode *declNode) auto moduleRecord = GetSourceTextModuleRecord(); ASSERT(moduleRecord != nullptr); util::StringView exportName = parser::SourceTextModuleRecord::DEFAULT_EXTERNAL_NAME; - util::StringView localName; + util::StringView localName = parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; if (declNode->IsFunctionDeclaration() || declNode->IsClassDeclaration()) { - const ir::Identifier *name = declNode->IsFunctionDeclaration() ? - declNode->AsFunctionDeclaration()->Function()->Id() : - declNode->AsClassDeclaration()->Definition()->Ident(); - localName = name == nullptr ? parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME : name->Name(); - } - if (declNode->IsExpression()) { - localName = parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; + localName = declNode->IsFunctionDeclaration() ? declNode->AsFunctionDeclaration()->Function()->GetName() : + declNode->AsClassDeclaration()->Definition()->GetName(); } ASSERT(!localName.Empty()); auto *entry = moduleRecord->NewEntry(exportName, localName); - if(!moduleRecord->AddLocalExportEntry(entry)) { + if (!moduleRecord->AddLocalExportEntry(entry)) { ThrowSyntaxError("Duplicate export name of '" + exportName.Mutf8() + "'", declNode->Start()); } } @@ -2063,7 +2062,7 @@ void ParserImpl::AddExportLocalEntryItem(const ir::Statement *declNode) for (const auto *binding : bindings) { auto *entry = moduleRecord->NewEntry( binding->Name(), binding->Name()); - if(!moduleRecord->AddLocalExportEntry(entry)) { + if (!moduleRecord->AddLocalExportEntry(entry)) { ThrowSyntaxError("Duplicate export name of '" + binding->Name().Mutf8() + "'", binding->Start()); } } @@ -2074,11 +2073,11 @@ void ParserImpl::AddExportLocalEntryItem(const ir::Statement *declNode) declNode->AsFunctionDeclaration()->Function()->Id() : declNode->AsClassDeclaration()->Definition()->Ident(); if (name == nullptr) { - ThrowSyntaxError("A class or function declaration without the default modifier mush have a name.", - declNode->Start()); + ThrowSyntaxError("A class or function declaration without the default modifier mush have a name.", + declNode->Start()); } auto *entry = moduleRecord->NewEntry(name->Name(), name->Name()); - if(!moduleRecord->AddLocalExportEntry(entry)) { + if (!moduleRecord->AddLocalExportEntry(entry)) { ThrowSyntaxError("Duplicate export name of '" + name->Name().Mutf8() + "'", name->Start()); } } diff --git a/es2panda/util/helpers.cpp b/es2panda/util/helpers.cpp index 84537cbe79..d1e0477f13 100644 --- a/es2panda/util/helpers.cpp +++ b/es2panda/util/helpers.cpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include namespace panda::es2panda::util { -- Gitee