* 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 <binder/scope.h>
namespace panda::es2panda::parser {
int SourceTextModuleRecord::AddModuleRequest(const ModuleRequestRecord record)
{
ASSERT(!record.source_.Empty());
hasLazyImport_ = hasLazyImport_ || record.isLazy_;
int moduleRequestsSize = static_cast<int>(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;
}
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));
CheckImplicitIndirectExport(entry);
}
void SourceTextModuleRecord::AddStarImportEntry(SourceTextModuleRecord::ImportEntry *entry)
{
ASSERT(!entry->localName_.Empty());
ASSERT(entry->importName_.Empty());
ASSERT(entry->moduleRequestIdx_ != -1);
namespaceImportEntries_.push_back(entry);
}
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);
if (CheckImplicitIndirectExport(entry)) {
return true;
}
if (!HasDuplicateExport(entry->exportName_)) {
localExportEntries_.insert(std::make_pair(entry->localName_, entry));
return true;
}
return false;
}
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;
}
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_);
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;
}
}