/* * 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 "sourceTextModuleRecord.h" #include namespace panda::es2panda::parser { int SourceTextModuleRecord::AddModuleRequest(const ModuleRequestRecord record) { ASSERT(!record.source_.Empty()); hasLazyImport_ = hasLazyImport_ || record.isLazy_; int moduleRequestsSize = static_cast(moduleRequestsMap_.size()); if (moduleRequestsMap_.find(record) == moduleRequestsMap_.end()) { moduleRequests_.emplace_back(record); } auto insertedRes = moduleRequestsMap_.insert(std::make_pair(record, 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) { CHECK_NOT_NULL(entry); ASSERT(entry != nullptr); 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' CheckImplicitIndirectExport(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) { CHECK_NOT_NULL(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 (CheckImplicitIndirectExport(entry)) { return true; } if (!HasDuplicateExport(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) { CHECK_NOT_NULL(entry); ASSERT(entry != nullptr); ASSERT(!entry->importName_.Empty()); ASSERT(!entry->exportName_.Empty()); ASSERT(entry->localName_.Empty()); ASSERT(entry->moduleRequestIdx_ != -1); if (!HasDuplicateExport(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::HasDuplicateExport(util::StringView exportName) const { for (auto const &entryUnit : localExportEntries_) { const SourceTextModuleRecord::ExportEntry *e = entryUnit.second; if (exportName == e->exportName_) { return true; } } for (const auto *e : indirectExportEntries_) { if (exportName == e->exportName_) { return true; } } return false; } bool SourceTextModuleRecord::CheckImplicitIndirectExport(SourceTextModuleRecord::ExportEntry *exportEntry) { CHECK_NOT_NULL(exportEntry); ASSERT(exportEntry != nullptr); ASSERT(!exportEntry->localName_.Empty()); auto regularImport = regularImportEntries_.find(exportEntry->localName_); if (regularImport != regularImportEntries_.end()) { ConvertLocalExportToIndirect(regularImport->second, exportEntry); return AddIndirectExportEntry(exportEntry); } return false; } void SourceTextModuleRecord::CheckImplicitIndirectExport(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; ConvertLocalExportToIndirect(importEntry, exportEntry); indirectExportEntries_.push_back(exportEntry); } localExportEntries_.erase(range.first, range.second); } void SourceTextModuleRecord::ConvertLocalExportToIndirect(SourceTextModuleRecord::ImportEntry *importEntry, SourceTextModuleRecord::ExportEntry *exportEntry) { CHECK_NOT_NULL(importEntry); 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(""); } void SourceTextModuleRecord::AssignIndexToModuleVariable(binder::ModuleScope *moduleScope) { uint32_t index = 0; for (auto it = localExportEntries_.begin(); it != localExportEntries_.end(); it = localExportEntries_.upper_bound(it->first)) { auto variable = CheckAndAssignIndex(moduleScope, it->first, &index); if (variable != nullptr && variable->IsModuleVariable() && variable->Declaration()->IsConstDecl()) { auto range = localExportEntries_.equal_range(it->first); for (auto local_iter = range.first; local_iter != range.second; local_iter++) { local_iter->second->SetAsConstant(); } } } index = 0; for (const auto &elem : regularImportEntries_) { CheckAndAssignIndex(moduleScope, elem.first, &index); } } binder::Variable *SourceTextModuleRecord::CheckAndAssignIndex(binder::ModuleScope *moduleScope, util::StringView name, uint32_t *index) const { auto modulevar = moduleScope->FindLocal(name); if (modulevar != nullptr) { moduleScope->AssignIndexToModuleVariable(name, *index); (*index)++; } return modulevar; } void SourceTextModuleRecord::RemoveDefaultLocalExportEntry() { util::StringView localName = parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME; localExportEntries_.erase(localName); } int SourceTextModuleRecord::GetModuleRequestIdx(const util::StringView localName) { for (const auto &it : regularImportEntries_) { if (it.first != localName) { continue; } return it.second->moduleRequestIdx_; } for (const auto &it : namespaceImportEntries_) { if (it->localName_ != localName) { continue; } return it->moduleRequestIdx_; } return SourceTextModuleRecord::INVALID_MODULEREQUEST_ID; } } // namespace panda::es2panda::parser