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