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