• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 #ifndef ES2PANDA_VARBINDER_ETSBINDER_H
17 #define ES2PANDA_VARBINDER_ETSBINDER_H
18 
19 #include "varbinder/TypedBinder.h"
20 #include "varbinder/recordTable.h"
21 #include "ir/ets/etsImportDeclaration.h"
22 #include "ir/ets/etsReExportDeclaration.h"
23 #include "ir/expressions/identifier.h"
24 #include "ir/module/importSpecifier.h"
25 #include "parser/program/program.h"
26 #include "util/importPathManager.h"
27 
28 namespace ark::es2panda::varbinder {
29 using AliasesByExportedNames = ArenaMap<util::StringView, util::StringView>;
30 using ModulesToExportedNamesWithAliases = ArenaMap<util::StringView, AliasesByExportedNames>;
31 
32 struct DynamicImportData {
33     const ir::ETSImportDeclaration *import;
34     const ir::AstNode *specifier;
35     Variable *variable;
36 };
37 
38 using DynamicImportVariables = ArenaUnorderedMap<const Variable *, DynamicImportData>;
39 
40 class ETSBinder : public TypedBinder {
41 public:
ETSBinder(ArenaAllocator * allocator)42     explicit ETSBinder(ArenaAllocator *allocator)
43         : TypedBinder(allocator),
44           globalRecordTable_(allocator, Program(), RecordTableFlags::NONE),
45           recordTable_(&globalRecordTable_),
46           externalRecordTable_(Allocator()->Adapter()),
47           defaultImports_(Allocator()->Adapter()),
48           dynamicImports_(Allocator()->Adapter()),
49           reExportImports_(Allocator()->Adapter()),
50           dynamicImportVars_(Allocator()->Adapter()),
51           importSpecifiers_(Allocator()->Adapter()),
52           selectiveExportAliasMultimap_(Allocator()->Adapter())
53     {
54         InitImplicitThisParam();
55     }
56 
57     NO_COPY_SEMANTIC(ETSBinder);
58     NO_MOVE_SEMANTIC(ETSBinder);
59     ~ETSBinder() override = default;
60 
Extension()61     ScriptExtension Extension() const override
62     {
63         return ScriptExtension::ETS;
64     }
65 
BindingOptions()66     ResolveBindingOptions BindingOptions() const override
67     {
68         return ResolveBindingOptions::BINDINGS;
69     }
70 
GetRecordTable()71     RecordTable *GetRecordTable()
72     {
73         return recordTable_;
74     }
75 
GetRecordTable()76     const RecordTable *GetRecordTable() const
77     {
78         return recordTable_;
79     }
80 
GetGlobalRecordTable()81     RecordTable *GetGlobalRecordTable()
82     {
83         return &globalRecordTable_;
84     }
85 
GetGlobalRecordTable()86     const RecordTable *GetGlobalRecordTable() const
87     {
88         return &globalRecordTable_;
89     }
90 
GetExternalRecordTable()91     ArenaMap<parser::Program *, RecordTable *> &GetExternalRecordTable()
92     {
93         return externalRecordTable_;
94     }
95 
GetExternalRecordTable()96     const ArenaMap<parser::Program *, RecordTable *> &GetExternalRecordTable() const
97     {
98         return externalRecordTable_;
99     }
100 
101     void HandleCustomNodes(ir::AstNode *childNode) override;
102 
103     void IdentifierAnalysis() override;
104     void BuildClassDefinition(ir::ClassDefinition *classDef) override;
105     void BuildClassProperty(const ir::ClassProperty *prop) override;
106     void LookupIdentReference(ir::Identifier *ident) override;
107     bool BuildInternalName(ir::ScriptFunction *scriptFunc) override;
108     void AddCompilableFunction(ir::ScriptFunction *func) override;
109 
110     void LookupTypeReference(ir::Identifier *ident, bool allowDynamicNamespaces);
111     void LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef);
112     void BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl);
113     void BuildMemberExpression(ir::MemberExpression *memberExpr);
114     void BuildMethodDefinition(ir::MethodDefinition *methodDef);
115     void BuildImportDeclaration(ir::ETSImportDeclaration *decl);
116     void BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *classInstance);
117     bool DetectNameConflict(const util::StringView localName, Variable *const var, Variable *const otherVar,
118                             const ir::StringLiteral *const importPath, bool overloadAllowed);
119     void AddSpecifiersToTopBindings(ir::AstNode *specifier, const ir::ETSImportDeclaration *import);
120     ArenaVector<parser::Program *> GetExternalProgram(const util::StringView &sourceName,
121                                                       const ir::StringLiteral *importPath);
122     bool AddImportNamespaceSpecifiersToTopBindings(ir::AstNode *specifier,
123                                                    const varbinder::Scope::VariableMap &globalBindings,
124                                                    const parser::Program *importProgram,
125                                                    const varbinder::GlobalScope *importGlobalScope,
126                                                    const ir::ETSImportDeclaration *import);
127     ir::ETSImportDeclaration *FindImportDeclInReExports(const ir::ETSImportDeclaration *const import,
128                                                         std::vector<ir::ETSImportDeclaration *> &viewedReExport,
129                                                         const util::StringView &imported,
130                                                         const ir::StringLiteral *const importPath);
131     bool AddImportSpecifiersToTopBindings(ir::AstNode *specifier, const varbinder::Scope::VariableMap &globalBindings,
132                                           const ir::ETSImportDeclaration *import,
133                                           const ArenaVector<parser::Program *> &recordRes,
134                                           std::vector<ir::ETSImportDeclaration *> viewedReExport);
135     void ValidateImportVariable(varbinder::Variable *const var, const ir::ETSImportDeclaration *const import,
136                                 const util::StringView &imported, const ir::StringLiteral *const importPath);
137     Variable *FindImportSpecifiersVariable(const util::StringView &imported,
138                                            const varbinder::Scope::VariableMap &globalBindings,
139                                            const ArenaVector<parser::Program *> &recordRes);
140     Variable *FindStaticBinding(const ArenaVector<parser::Program *> &recordRes, const ir::StringLiteral *importPath);
141     void AddSpecifiersToTopBindings(
142         ir::AstNode *specifier, const ir::ETSImportDeclaration *import, ir::StringLiteral *path,
143         std::vector<ir::ETSImportDeclaration *> viewedReExport = std::vector<ir::ETSImportDeclaration *>());
144     void AddDynamicSpecifiersToTopBindings(ir::AstNode *specifier, const ir::ETSImportDeclaration *import);
145 
146     void ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl);
147     void ResolveMethodDefinition(ir::MethodDefinition *methodDef);
148     LocalScope *ResolvePropertyReference(ir::ClassProperty *prop, ClassScope *scope);
149     void ResolveEnumDeclaration(ir::TSEnumDeclaration *enumDecl);
150     void InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl);
151     void BuildExternalProgram(parser::Program *extProgram);
152     void BuildProgram();
153 
154     void BuildFunctionName(const ir::ScriptFunction *func) const;
155     bool BuildInternalNameWithCustomRecordTable(ir::ScriptFunction *scriptFunc, RecordTable *recordTable);
156     void BuildProxyMethod(ir::ScriptFunction *func, const util::StringView &containingClassName, bool isStatic,
157                           bool isExternal);
158     void AddFunctionThisParam(ir::ScriptFunction *func);
159 
SetDefaultImports(ArenaVector<ir::ETSImportDeclaration * > defaultImports)160     void SetDefaultImports(ArenaVector<ir::ETSImportDeclaration *> defaultImports)
161     {
162         defaultImports_ = std::move(defaultImports);
163     }
164 
AddDynamicImport(ir::ETSImportDeclaration * import)165     void AddDynamicImport(ir::ETSImportDeclaration *import)
166     {
167         ASSERT(import->Language().IsDynamic());
168         dynamicImports_.push_back(import);
169     }
170 
DynamicImports()171     const ArenaVector<ir::ETSImportDeclaration *> &DynamicImports() const
172     {
173         return dynamicImports_;
174     }
175 
AddReExportImport(ir::ETSReExportDeclaration * reExport)176     void AddReExportImport(ir::ETSReExportDeclaration *reExport)
177     {
178         reExportImports_.push_back(reExport);
179     }
180 
ReExportImports()181     const ArenaVector<ir::ETSReExportDeclaration *> &ReExportImports() const
182     {
183         return reExportImports_;
184     }
185 
DynamicImportVars()186     const DynamicImportVariables &DynamicImportVars() const
187     {
188         return dynamicImportVars_;
189     }
190 
DefaultExport()191     const ir::AstNode *DefaultExport()
192     {
193         return defaultExport_;
194     }
195 
SetDefaultExport(ir::AstNode * defaultExport)196     void SetDefaultExport(ir::AstNode *defaultExport)
197     {
198         defaultExport_ = defaultExport;
199     }
200 
201     /* Returns the list of programs belonging to the same compilation unit based on a program path */
GetProgramList(const util::StringView & path)202     ArenaVector<parser::Program *> GetProgramList(const util::StringView &path) const
203     {
204         for (const auto &extRecords : globalRecordTable_.Program()->ExternalSources()) {
205             for (const auto &program : extRecords.second) {
206                 if (program->AbsoluteName() == path) {
207                     return extRecords.second;
208                 }
209 
210                 // in case of importing a package folder, the path could not be resolved to a specific file
211                 if (program->IsPackageModule() && program->SourceFileFolder() == path) {
212                     return extRecords.second;
213                 }
214             }
215         }
216 
217         return ArenaVector<parser::Program *>(Allocator()->Adapter());
218     }
219 
220     bool IsDynamicModuleVariable(const Variable *var) const;
221     bool IsDynamicNamespaceVariable(const Variable *var) const;
222     const DynamicImportData *DynamicImportDataForVar(const Variable *var) const;
223 
224     void ResolveReferenceForScope(ir::AstNode *node, Scope *scope);
225     void ResolveReferencesForScope(ir::AstNode const *parent, Scope *scope);
226 
227     void ResolveReferencesForScopeWithContext(ir::AstNode *node, Scope *scope);
228 
229     bool CheckForRedeclarationError(const util::StringView &localName, Variable *const var,
230                                     const ir::StringLiteral *const importPath);
231 
AddSelectiveExportAlias(util::StringView const & path,util::StringView const & key,util::StringView const & value)232     bool AddSelectiveExportAlias(util::StringView const &path, util::StringView const &key,
233                                  util::StringView const &value)
234     {
235         if (auto foundMap = selectiveExportAliasMultimap_.find(path); foundMap != selectiveExportAliasMultimap_.end()) {
236             return foundMap->second.insert({key, value}).second;
237         }
238 
239         ArenaMap<util::StringView, util::StringView> map(Allocator()->Adapter());
240         bool insertResult = map.insert({key, value}).second;
241         selectiveExportAliasMultimap_.insert({path, map});
242         return insertResult;
243     }
244 
GetSelectiveExportAliasMultimap()245     [[nodiscard]] const ModulesToExportedNamesWithAliases &GetSelectiveExportAliasMultimap() const noexcept
246     {
247         return selectiveExportAliasMultimap_;
248     }
249 
FindNameInAliasMap(const util::StringView & pathAsKey,const util::StringView & aliasName)250     util::StringView FindNameInAliasMap(const util::StringView &pathAsKey, const util::StringView &aliasName)
251     {
252         if (auto relatedMap = selectiveExportAliasMultimap_.find(pathAsKey);
253             relatedMap != selectiveExportAliasMultimap_.end()) {
254             if (auto item = relatedMap->second.find(aliasName); item != relatedMap->second.end()) {
255                 return item->second;
256             }
257         }
258 
259         return "";
260     }
261 
FindLocalNameForImport(const ir::ImportSpecifier * const importSpecifier,util::StringView & imported,const ir::StringLiteral * const importPath)262     util::StringView FindLocalNameForImport(const ir::ImportSpecifier *const importSpecifier,
263                                             util::StringView &imported, const ir::StringLiteral *const importPath)
264     {
265         if (importSpecifier->Local() != nullptr) {
266             auto checkImportPathAndName = [&importPath, &imported](const auto &savedSpecifier) {
267                 return importPath->Str() != savedSpecifier.first && imported == savedSpecifier.second;
268             };
269             if (!std::any_of(importSpecifiers_.begin(), importSpecifiers_.end(), checkImportPathAndName)) {
270                 TopScope()->EraseBinding(imported);
271             }
272 
273             importSpecifiers_.emplace_back(importPath->Str(), imported);
274 
275             return importSpecifier->Local()->Name();
276         }
277 
278         return imported;
279     }
280 
281 private:
282     void BuildClassDefinitionImpl(ir::ClassDefinition *classDef);
283     void InitImplicitThisParam();
284     void HandleStarImport(ir::TSQualifiedName *importName, util::StringView fullPath);
285     void ImportGlobalProperties(const ir::ClassDefinition *classDef);
286     bool ImportGlobalPropertiesForNotDefaultedExports(varbinder::Variable *var, const util::StringView &name,
287                                                       const ir::ClassElement *classElement);
288     void InsertForeignBinding(ir::AstNode *specifier, const ir::ETSImportDeclaration *import,
289                               const util::StringView &name, Variable *var);
290     void ImportAllForeignBindings(ir::AstNode *specifier, const varbinder::Scope::VariableMap &globalBindings,
291                                   const parser::Program *importProgram, const varbinder::GlobalScope *importGlobalScope,
292                                   const ir::ETSImportDeclaration *import);
293 
294     RecordTable globalRecordTable_;
295     RecordTable *recordTable_;
296     ArenaMap<parser::Program *, RecordTable *> externalRecordTable_;
297     ArenaVector<ir::ETSImportDeclaration *> defaultImports_;
298     ArenaVector<ir::ETSImportDeclaration *> dynamicImports_;
299     ArenaVector<ir::ETSReExportDeclaration *> reExportImports_;
300     DynamicImportVariables dynamicImportVars_;
301     ir::Identifier *thisParam_ {};
302     ArenaVector<std::pair<util::StringView, util::StringView>> importSpecifiers_;
303     ir::AstNode *defaultExport_ {};
304     ModulesToExportedNamesWithAliases selectiveExportAliasMultimap_;
305 
306     friend class RecordTableContext;
307 };
308 
309 class RecordTableContext {
310 public:
RecordTableContext(ETSBinder * varBinder,parser::Program * extProgram)311     RecordTableContext(ETSBinder *varBinder, parser::Program *extProgram)
312         : varBinder_(varBinder), savedRecordTable_(varBinder->recordTable_)
313     {
314         varBinder->recordTable_ = varBinder->externalRecordTable_[extProgram];
315     }
316 
317     NO_COPY_SEMANTIC(RecordTableContext);
318     NO_MOVE_SEMANTIC(RecordTableContext);
319 
~RecordTableContext()320     ~RecordTableContext()
321     {
322         varBinder_->recordTable_ = savedRecordTable_;
323     }
324 
325 private:
326     ETSBinder *varBinder_;
327     RecordTable *savedRecordTable_;
328 };
329 
330 }  // namespace ark::es2panda::varbinder
331 
332 #endif
333