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