• 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           reexportedNames_(Allocator()->Adapter()),
51           dynamicImportVars_(Allocator()->Adapter()),
52           importSpecifiers_(Allocator()->Adapter()),
53           selectiveExportAliasMultimap_(Allocator()->Adapter())
54     {
55         InitImplicitThisParam();
56     }
57 
58     NO_COPY_SEMANTIC(ETSBinder);
59     NO_MOVE_SEMANTIC(ETSBinder);
60     ~ETSBinder() override = default;
61 
Extension()62     ScriptExtension Extension() const override
63     {
64         return ScriptExtension::ETS;
65     }
66 
BindingOptions()67     ResolveBindingOptions BindingOptions() const override
68     {
69         return ResolveBindingOptions::BINDINGS;
70     }
71 
GetRecordTable()72     RecordTable *GetRecordTable()
73     {
74         return recordTable_;
75     }
76 
GetRecordTable()77     const RecordTable *GetRecordTable() const
78     {
79         return recordTable_;
80     }
81 
SetRecordTable(RecordTable * table)82     void SetRecordTable(RecordTable *table)
83     {
84         recordTable_ = table;
85     }
86 
GetGlobalRecordTable()87     RecordTable *GetGlobalRecordTable()
88     {
89         return &globalRecordTable_;
90     }
91 
GetGlobalRecordTable()92     const RecordTable *GetGlobalRecordTable() const
93     {
94         return &globalRecordTable_;
95     }
96 
GetExternalRecordTable()97     ArenaMap<parser::Program *, RecordTable *> &GetExternalRecordTable()
98     {
99         return externalRecordTable_;
100     }
101 
GetExternalRecordTable()102     const ArenaMap<parser::Program *, RecordTable *> &GetExternalRecordTable() const
103     {
104         return externalRecordTable_;
105     }
106 
107     void HandleCustomNodes(ir::AstNode *childNode) override;
108 
109     void IdentifierAnalysis() override;
110     void BuildClassDefinition(ir::ClassDefinition *classDef) override;
111     void BuildObjectExpression(ir::ObjectExpression *obj);
112     void BuildETSTypeReference(ir::ETSTypeReference *typeRef);
113     void BuildClassProperty(const ir::ClassProperty *prop) override;
114     void LookupIdentReference(ir::Identifier *ident) override;
115     bool BuildInternalName(ir::ScriptFunction *scriptFunc) override;
116     void AddCompilableFunction(ir::ScriptFunction *func) override;
117 
118     void LookupTypeReference(ir::Identifier *ident, bool allowDynamicNamespaces);
119     void LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef);
120     void BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl);
121     void BuildMemberExpression(ir::MemberExpression *memberExpr);
122     void BuildMethodDefinition(ir::MethodDefinition *methodDef);
123     void BuildAnnotationDeclaration(ir::AnnotationDeclaration *annoDecl);
124     void BuildAnnotationUsage(ir::AnnotationUsage *annoUsage);
125     void BuildImportDeclaration(ir::ETSImportDeclaration *decl);
126     void ValidateReexportDeclaration(ir::ETSReExportDeclaration *decl);
127     void ValidateReexports();
128     bool ReexportPathMatchesImportPath(const ir::ETSReExportDeclaration *const reexport,
129                                        const ir::ETSImportDeclaration *const import) const;
130     Variable *ValidateImportSpecifier(const ir::ImportSpecifier *const specifier,
131                                       const ir::ETSImportDeclaration *const import,
132                                       std::vector<ir::ETSImportDeclaration *> viewedReExport);
133     void BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *classInstance);
134     bool DetectNameConflict(const util::StringView localName, Variable *const var, Variable *const otherVar,
135                             const ir::StringLiteral *const importPath, bool overloadAllowed);
136     void AddSpecifiersToTopBindings(ir::AstNode *specifier, const ir::ETSImportDeclaration *import);
137     ArenaVector<parser::Program *> GetExternalProgram(const util::StringView &sourceName,
138                                                       const ir::StringLiteral *importPath);
139     bool AddImportNamespaceSpecifiersToTopBindings(ir::AstNode *specifier,
140                                                    const varbinder::Scope::VariableMap &globalBindings,
141                                                    const parser::Program *importProgram,
142                                                    const varbinder::GlobalScope *importGlobalScope,
143                                                    const ir::ETSImportDeclaration *import);
144     ir::ETSImportDeclaration *FindImportDeclInReExports(const ir::ETSImportDeclaration *const import,
145                                                         std::vector<ir::ETSImportDeclaration *> &viewedReExport,
146                                                         const util::StringView &imported,
147                                                         const ir::StringLiteral *const importPath);
148     bool AddImportSpecifiersToTopBindings(ir::AstNode *specifier, const varbinder::Scope::VariableMap &globalBindings,
149                                           const ir::ETSImportDeclaration *import,
150                                           const ArenaVector<parser::Program *> &recordRes,
151                                           std::vector<ir::ETSImportDeclaration *> viewedReExport);
152     void ValidateImportVariable(varbinder::Variable *const var, const ir::ETSImportDeclaration *const import,
153                                 const util::StringView &imported, const ir::StringLiteral *const importPath);
154     Variable *FindImportSpecifiersVariable(const util::StringView &imported,
155                                            const varbinder::Scope::VariableMap &globalBindings,
156                                            const ArenaVector<parser::Program *> &recordRes);
157     Variable *FindStaticBinding(const ArenaVector<parser::Program *> &recordRes, const ir::StringLiteral *importPath);
158     void AddSpecifiersToTopBindings(
159         ir::AstNode *specifier, const ir::ETSImportDeclaration *import, ir::StringLiteral *path,
160         std::vector<ir::ETSImportDeclaration *> viewedReExport = std::vector<ir::ETSImportDeclaration *>());
161     void AddDynamicSpecifiersToTopBindings(ir::AstNode *specifier, const ir::ETSImportDeclaration *import);
162 
163     void ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl);
164     void ResolveMethodDefinition(ir::MethodDefinition *methodDef);
165     LocalScope *ResolvePropertyReference(ir::ClassProperty *prop, ClassScope *scope);
166     void ResolveEnumDeclaration(ir::TSEnumDeclaration *enumDecl);
167     void InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl);
168     void BuildExternalProgram(parser::Program *extProgram);
169     void BuildProgram();
170 
171     void BuildFunctionName(const ir::ScriptFunction *func) const;
172     bool BuildInternalNameWithCustomRecordTable(ir::ScriptFunction *scriptFunc, RecordTable *recordTable);
173     void BuildProxyMethod(ir::ScriptFunction *func, const util::StringView &containingClassName, bool isExternal);
174     void AddFunctionThisParam(ir::ScriptFunction *func);
175 
SetDefaultImports(ArenaVector<ir::ETSImportDeclaration * > defaultImports)176     void SetDefaultImports(ArenaVector<ir::ETSImportDeclaration *> defaultImports)
177     {
178         defaultImports_ = std::move(defaultImports);
179     }
180 
AddDynamicImport(ir::ETSImportDeclaration * import)181     void AddDynamicImport(ir::ETSImportDeclaration *import)
182     {
183         ASSERT(import->Language().IsDynamic());
184         dynamicImports_.push_back(import);
185     }
186 
DynamicImports()187     const ArenaVector<ir::ETSImportDeclaration *> &DynamicImports() const
188     {
189         return dynamicImports_;
190     }
191 
AddReExportImport(ir::ETSReExportDeclaration * reExport)192     void AddReExportImport(ir::ETSReExportDeclaration *reExport)
193     {
194         reExportImports_.push_back(reExport);
195     }
196 
ReExportImports()197     const ArenaVector<ir::ETSReExportDeclaration *> &ReExportImports() const
198     {
199         return reExportImports_;
200     }
201 
DynamicImportVars()202     const DynamicImportVariables &DynamicImportVars() const
203     {
204         return dynamicImportVars_;
205     }
206 
DefaultExport()207     const ir::AstNode *DefaultExport()
208     {
209         return defaultExport_;
210     }
211 
SetDefaultExport(ir::AstNode * defaultExport)212     void SetDefaultExport(ir::AstNode *defaultExport)
213     {
214         defaultExport_ = defaultExport;
215     }
216 
217     /* Returns the list of programs belonging to the same compilation unit based on a program path */
218     ArenaVector<parser::Program *> GetProgramList(const util::StringView &path) const;
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     ArenaSet<util::StringView> reexportedNames_;
301     DynamicImportVariables dynamicImportVars_;
302     ir::Identifier *thisParam_ {};
303     ArenaVector<std::pair<util::StringView, util::StringView>> importSpecifiers_;
304     ir::AstNode *defaultExport_ {};
305     ModulesToExportedNamesWithAliases selectiveExportAliasMultimap_;
306 
307     friend class RecordTableContext;
308 };
309 
310 class RecordTableContext {
311 public:
RecordTableContext(ETSBinder * varBinder,parser::Program * extProgram)312     RecordTableContext(ETSBinder *varBinder, parser::Program *extProgram)
313         : varBinder_(varBinder), savedRecordTable_(varBinder->recordTable_)
314     {
315         varBinder->recordTable_ = varBinder->externalRecordTable_[extProgram];
316     }
317 
318     NO_COPY_SEMANTIC(RecordTableContext);
319     NO_MOVE_SEMANTIC(RecordTableContext);
320 
~RecordTableContext()321     ~RecordTableContext()
322     {
323         varBinder_->recordTable_ = savedRecordTable_;
324     }
325 
326 private:
327     ETSBinder *varBinder_;
328     RecordTable *savedRecordTable_;
329 };
330 
331 }  // namespace ark::es2panda::varbinder
332 
333 #endif
334