• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "sourceTextModuleRecord.h"
17 #include <binder/scope.h>
18 
19 namespace panda::es2panda::parser {
AddModuleRequest(const ModuleRequestRecord record)20     int SourceTextModuleRecord::AddModuleRequest(const ModuleRequestRecord record)
21     {
22         ASSERT(!record.source_.Empty());
23         hasLazyImport_ = hasLazyImport_ || record.isLazy_;
24 
25         int moduleRequestsSize = static_cast<int>(moduleRequestsMap_.size());
26         if (moduleRequestsMap_.find(record) == moduleRequestsMap_.end()) {
27             moduleRequests_.emplace_back(record);
28         }
29         auto insertedRes = moduleRequestsMap_.insert(std::make_pair(record, moduleRequestsSize));
30         return insertedRes.first->second;
31     }
32 
33     // import x from 'test.js'
34     // import {x} from 'test.js'
35     // import {x as y} from 'test.js'
36     // import defaultExport from 'test.js'
AddImportEntry(SourceTextModuleRecord::ImportEntry * entry)37     void SourceTextModuleRecord::AddImportEntry(SourceTextModuleRecord::ImportEntry *entry)
38     {
39         CHECK_NOT_NULL(entry);
40         ASSERT(entry != nullptr);
41         ASSERT(!entry->importName_.Empty());
42         ASSERT(!entry->localName_.Empty());
43         ASSERT(entry->moduleRequestIdx_ != -1);
44         regularImportEntries_.insert(std::make_pair(entry->localName_, entry));
45         // the implicit indirect exports should be insert into indirectExportsEntries
46         // when add an ImportEntry.
47         // e.g. export { x }; import { x } from 'test.js'
48         CheckImplicitIndirectExport(entry);
49     }
50 
51     // import * as x from 'test.js'
AddStarImportEntry(SourceTextModuleRecord::ImportEntry * entry)52     void SourceTextModuleRecord::AddStarImportEntry(SourceTextModuleRecord::ImportEntry *entry)
53     {
54         ASSERT(!entry->localName_.Empty());
55         ASSERT(entry->importName_.Empty());
56         ASSERT(entry->moduleRequestIdx_ != -1);
57         namespaceImportEntries_.push_back(entry);
58     }
59 
60     // export {x}
61     // export {x as y}
62     // export VariableStatement
63     // export Declaration
64     // export default ...
AddLocalExportEntry(SourceTextModuleRecord::ExportEntry * entry)65     bool SourceTextModuleRecord::AddLocalExportEntry(SourceTextModuleRecord::ExportEntry *entry)
66     {
67         CHECK_NOT_NULL(entry);
68         ASSERT(entry->importName_.Empty());
69         ASSERT(!entry->localName_.Empty());
70         ASSERT(!entry->exportName_.Empty());
71         ASSERT(entry->moduleRequestIdx_ == -1);
72 
73         // the implicit indirect exports should be insert into indirectExportsEntries
74         // when add an ExportEntry.
75         // e.g. import { x } from 'test.js'; export { x }
76         if (CheckImplicitIndirectExport(entry)) {
77             return true;
78         }
79         if (!HasDuplicateExport(entry->exportName_)) {
80             localExportEntries_.insert(std::make_pair(entry->localName_, entry));
81             return true;
82         }
83         return false;
84     }
85 
86     // export {x} from 'test.js'
87     // export {x as y} from 'test.js'
88     // import { x } from 'test.js'; export { x }
AddIndirectExportEntry(SourceTextModuleRecord::ExportEntry * entry)89     bool SourceTextModuleRecord::AddIndirectExportEntry(SourceTextModuleRecord::ExportEntry *entry)
90     {
91         CHECK_NOT_NULL(entry);
92         ASSERT(entry != nullptr);
93         ASSERT(!entry->importName_.Empty());
94         ASSERT(!entry->exportName_.Empty());
95         ASSERT(entry->localName_.Empty());
96         ASSERT(entry->moduleRequestIdx_ != -1);
97         if (!HasDuplicateExport(entry->exportName_)) {
98             indirectExportEntries_.push_back(entry);
99             return true;
100         }
101         return false;
102     }
103 
104     // export * from 'test.js'
AddStarExportEntry(SourceTextModuleRecord::ExportEntry * entry)105     void SourceTextModuleRecord::AddStarExportEntry(SourceTextModuleRecord::ExportEntry *entry)
106     {
107         ASSERT(entry->importName_.Empty());
108         ASSERT(entry->localName_.Empty());
109         ASSERT(entry->exportName_.Empty());
110         ASSERT(entry->moduleRequestIdx_ != -1);
111         starExportEntries_.push_back(entry);
112     }
113 
HasDuplicateExport(util::StringView exportName) const114     bool SourceTextModuleRecord::HasDuplicateExport(util::StringView exportName) const
115     {
116         for (auto const &entryUnit : localExportEntries_) {
117             const SourceTextModuleRecord::ExportEntry *e = entryUnit.second;
118             if (exportName == e->exportName_) {
119                 return true;
120             }
121         }
122 
123         for (const auto *e : indirectExportEntries_) {
124             if (exportName == e->exportName_) {
125                 return true;
126             }
127         }
128 
129         return false;
130     }
131 
CheckImplicitIndirectExport(SourceTextModuleRecord::ExportEntry * exportEntry)132     bool SourceTextModuleRecord::CheckImplicitIndirectExport(SourceTextModuleRecord::ExportEntry *exportEntry)
133     {
134         CHECK_NOT_NULL(exportEntry);
135         ASSERT(exportEntry != nullptr);
136         ASSERT(!exportEntry->localName_.Empty());
137         auto regularImport = regularImportEntries_.find(exportEntry->localName_);
138         if (regularImport != regularImportEntries_.end()) {
139             ConvertLocalExportToIndirect(regularImport->second, exportEntry);
140             return AddIndirectExportEntry(exportEntry);
141         }
142         return false;
143     }
144 
CheckImplicitIndirectExport(SourceTextModuleRecord::ImportEntry * importEntry)145     void SourceTextModuleRecord::CheckImplicitIndirectExport(SourceTextModuleRecord::ImportEntry *importEntry)
146     {
147         ASSERT(!importEntry->localName_.Empty());
148         auto range = localExportEntries_.equal_range(importEntry->localName_);
149         // not found implicit indirect
150         if (range.first == range.second) {
151             return;
152         }
153 
154         for (auto it = range.first; it != range.second; ++it) {
155             SourceTextModuleRecord::ExportEntry *exportEntry = it->second;
156             ConvertLocalExportToIndirect(importEntry, exportEntry);
157             indirectExportEntries_.push_back(exportEntry);
158         }
159         localExportEntries_.erase(range.first, range.second);
160     }
161 
ConvertLocalExportToIndirect(SourceTextModuleRecord::ImportEntry * importEntry,SourceTextModuleRecord::ExportEntry * exportEntry)162     void SourceTextModuleRecord::ConvertLocalExportToIndirect(SourceTextModuleRecord::ImportEntry *importEntry,
163                                                               SourceTextModuleRecord::ExportEntry *exportEntry)
164     {
165         CHECK_NOT_NULL(importEntry);
166         ASSERT(exportEntry->importName_.Empty());
167         ASSERT(exportEntry->moduleRequestIdx_ == -1);
168         ASSERT(!importEntry->importName_.Empty());
169         ASSERT(importEntry->moduleRequestIdx_ != -1);
170         exportEntry->importName_ = importEntry->importName_;
171         exportEntry->moduleRequestIdx_ = importEntry->moduleRequestIdx_;
172         exportEntry->localName_ = util::StringView("");
173     }
174 
AssignIndexToModuleVariable(binder::ModuleScope * moduleScope)175     void SourceTextModuleRecord::AssignIndexToModuleVariable(binder::ModuleScope *moduleScope)
176     {
177         uint32_t index = 0;
178         for (auto it = localExportEntries_.begin(); it != localExportEntries_.end();
179              it = localExportEntries_.upper_bound(it->first)) {
180             auto variable = CheckAndAssignIndex(moduleScope, it->first, &index);
181             if (variable != nullptr && variable->IsModuleVariable() && variable->Declaration()->IsConstDecl()) {
182                 auto range = localExportEntries_.equal_range(it->first);
183                 for (auto local_iter = range.first; local_iter != range.second; local_iter++) {
184                     local_iter->second->SetAsConstant();
185                 }
186             }
187         }
188 
189         index = 0;
190         for (const auto &elem : regularImportEntries_) {
191             CheckAndAssignIndex(moduleScope, elem.first, &index);
192         }
193     }
194 
CheckAndAssignIndex(binder::ModuleScope * moduleScope,util::StringView name,uint32_t * index) const195     binder::Variable *SourceTextModuleRecord::CheckAndAssignIndex(binder::ModuleScope *moduleScope,
196                                                                   util::StringView name,
197                                                                   uint32_t *index) const
198     {
199         auto modulevar = moduleScope->FindLocal(name);
200         if (modulevar != nullptr) {
201             moduleScope->AssignIndexToModuleVariable(name, *index);
202             (*index)++;
203         }
204         return modulevar;
205     }
206 
RemoveDefaultLocalExportEntry()207     void SourceTextModuleRecord::RemoveDefaultLocalExportEntry()
208     {
209         util::StringView localName = parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME;
210         localExportEntries_.erase(localName);
211     }
212 
GetModuleRequestIdx(const util::StringView localName)213     int SourceTextModuleRecord::GetModuleRequestIdx(const util::StringView localName)
214     {
215         for (const auto &it : regularImportEntries_) {
216             if (it.first != localName) {
217                 continue;
218             }
219 
220             return it.second->moduleRequestIdx_;
221         }
222 
223         for (const auto &it : namespaceImportEntries_) {
224             if (it->localName_ != localName) {
225                 continue;
226             }
227 
228             return it->moduleRequestIdx_;
229         }
230 
231         return SourceTextModuleRecord::INVALID_MODULEREQUEST_ID;
232     }
233 } // namespace panda::es2panda::parser
234