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#include "scope.h" 17 18#include "varbinder/declaration.h" 19#include "util/helpers.h" 20#include "varbinder/tsBinding.h" 21#include "varbinder/variable.h" 22#include "varbinder/variableFlags.h" 23#include "ir/astNode.h" 24#include "ir/expressions/identifier.h" 25#include "ir/statements/classDeclaration.h" 26#include "ir/base/classDefinition.h" 27#include "ir/base/scriptFunction.h" 28#include "ir/base/classProperty.h" 29#include "ir/base/methodDefinition.h" 30#include "ir/module/exportAllDeclaration.h" 31#include "ir/module/exportNamedDeclaration.h" 32#include "ir/module/exportSpecifier.h" 33#include "ir/module/importDeclaration.h" 34#include "ir/expressions/literals/stringLiteral.h" 35#include "ir/expressions/literals/booleanLiteral.h" 36#include "ir/ts/tsInterfaceDeclaration.h" 37#include "ir/ts/tsEnumDeclaration.h" 38#include "ir/ts/tsTypeAliasDeclaration.h" 39#include "compiler/base/literals.h" 40#include "macros.h" 41#include "util/ustring.h" 42#include "generated/signatures.h" 43#include "public/public.h" 44 45namespace ark::es2panda::varbinder { 46VariableScope *Scope::EnclosingVariableScope() 47{ 48 Scope *iter = this; 49 50 while (iter != nullptr) { 51 if (iter->IsVariableScope()) { 52 return iter->AsVariableScope(); 53 } 54 55 iter = iter->Parent(); 56 } 57 58 return nullptr; 59} 60 61const VariableScope *Scope::EnclosingVariableScope() const 62{ 63 const auto *iter = this; 64 65 while (iter != nullptr) { 66 if (iter->IsVariableScope()) { 67 return iter->AsVariableScope(); 68 } 69 70 iter = iter->Parent(); 71 } 72 73 return nullptr; 74} 75 76bool Scope::IsSuperscopeOf(const varbinder::Scope *subscope) const 77{ 78 while (subscope != nullptr) { 79 if (subscope == this) { 80 return true; 81 } 82 subscope = ir::AstNode::EnclosingScope(subscope->Node()->Parent()); 83 } 84 return false; 85} 86 87// NOTE(psiket): Duplication 88ClassScope *Scope::EnclosingClassScope() 89{ 90 Scope *iter = this; 91 92 while (iter != nullptr) { 93 if (iter->IsClassScope()) { 94 return iter->AsClassScope(); 95 } 96 97 iter = iter->Parent(); 98 } 99 100 return nullptr; 101} 102 103const ClassScope *Scope::EnclosingClassScope() const 104{ 105 const auto *iter = this; 106 107 while (iter != nullptr) { 108 if (iter->IsVariableScope()) { 109 return iter->AsClassScope(); 110 } 111 112 iter = iter->Parent(); 113 } 114 115 return nullptr; 116} 117 118Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const 119{ 120 if ((options & ResolveBindingOptions::INTERFACES) != 0) { 121 std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name); 122 util::StringView interfaceNameView(tsBindingName); 123 124 auto res = bindings_.find(interfaceNameView); 125 if (res != bindings_.end()) { 126 return res->second; 127 } 128 129 if ((options & ResolveBindingOptions::BINDINGS) == 0) { 130 return nullptr; 131 } 132 } 133 134 auto res = bindings_.find(name); 135 if (res == bindings_.end()) { 136 return nullptr; 137 } 138 139 return res->second; 140} 141 142Scope::InsertResult Scope::InsertBinding(const util::StringView &name, Variable *const var) 143{ 144 ASSERT(var != nullptr); 145 auto insertResult = bindings_.emplace(name, var); 146 if (insertResult.second) { 147 decls_.push_back(var->Declaration()); 148 } 149 150 return insertResult; 151} 152 153Scope::InsertResult Scope::TryInsertBinding(const util::StringView &name, Variable *const var) 154{ 155 ASSERT(var != nullptr); 156 return bindings_.try_emplace(name, var); 157} 158 159void Scope::MergeBindings(VariableMap const &bindings) 160{ 161 for (auto &[k, v] : bindings) { 162 bindings_.try_emplace(k, v); 163 } 164} 165 166Scope::VariableMap::size_type Scope::EraseBinding(const util::StringView &name) 167{ 168 if (auto toBeErased = bindings_.find(name); 169 toBeErased == bindings_.end() || 170 (toBeErased->second->IsLocalVariable() && 171 toBeErased->second->AsLocalVariable()->Declaration()->Node()->IsImportNamespaceSpecifier())) { 172 return 0; 173 } 174 175 return bindings_.erase(name); 176} 177 178ConstScopeFindResult Scope::FindInGlobal(const util::StringView &name, const ResolveBindingOptions options) const 179{ 180 const auto *scopeIter = this; 181 const auto *scopeParent = this->Parent(); 182 // One scope below true global is ETSGLOBAL 183 while (scopeParent != nullptr && !scopeParent->IsGlobalScope()) { 184 scopeIter = scopeParent; 185 scopeParent = scopeIter->Parent(); 186 } 187 188 auto *resolved = scopeIter->FindLocal(name, options); 189 if (resolved == nullptr && scopeParent != nullptr) { 190 // If the variable cannot be found in the scope of the local ETSGLOBAL, than we still need to check the true 191 // global scope which contains all the imported ETSGLOBALs 192 resolved = scopeParent->FindLocal(name, options); 193 } 194 195 return {name, scopeIter, 0, 0, resolved}; 196} 197 198ConstScopeFindResult Scope::FindInFunctionScope(const util::StringView &name, const ResolveBindingOptions options) const 199{ 200 const auto *scopeIter = this; 201 while (scopeIter != nullptr && !scopeIter->IsGlobalScope()) { 202 if (!scopeIter->IsClassScope()) { 203 if (auto *const resolved = scopeIter->FindLocal(name, options); resolved != nullptr) { 204 return ConstScopeFindResult(name, scopeIter, 0, 0, resolved); 205 } 206 } 207 scopeIter = scopeIter->Parent(); 208 } 209 210 return ConstScopeFindResult(name, scopeIter, 0, 0, nullptr); 211} 212 213ScopeFindResult Scope::Find(const util::StringView &name, const ResolveBindingOptions options) 214{ 215 return FindImpl<ScopeFindResult>(this, name, options); 216} 217 218ConstScopeFindResult Scope::Find(const util::StringView &name, const ResolveBindingOptions options) const 219{ 220 return FindImpl<ConstScopeFindResult>(this, name, options); 221} 222 223Decl *Scope::FindDecl(const util::StringView &name) const 224{ 225 for (auto *it : decls_) { 226 if (it->Name() == name) { 227 return it; 228 } 229 } 230 231 return nullptr; 232} 233 234std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitor &visitor) 235{ 236 auto *iter = this; 237 238 while (iter != nullptr) { 239 auto *v = iter->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS); 240 241 if (v != nullptr && visitor(v)) { 242 return {iter, true}; 243 } 244 245 if (iter->IsFunctionVariableScope()) { 246 break; 247 } 248 249 iter = iter->Parent(); 250 } 251 252 return {iter, false}; 253} 254 255Variable *Scope::AddLocalVar(ArenaAllocator *allocator, Decl *newDecl) 256{ 257 auto [scope, shadowed] = 258 IterateShadowedVariables(newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); }); 259 260 if (shadowed) { 261 return nullptr; 262 } 263 264 VariableFlags varFlags = VariableFlags::HOIST_VAR | VariableFlags::LEXICAL_VAR; 265 if (scope->IsGlobalScope()) { 266 return scope->InsertBinding(newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)).first->second; 267 } 268 269 return scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags); 270} 271 272Variable *Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, 273 [[maybe_unused]] ScriptExtension extension) 274{ 275 VariableFlags flags = VariableFlags::LEXICAL; 276 switch (newDecl->Type()) { 277 case DeclType::VAR: { 278 return AddLocalVar(allocator, newDecl); 279 } 280 case DeclType::ENUM: { 281 return bindings_.insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)}).first->second; 282 } 283 case DeclType::ENUM_LITERAL: { 284 return bindings_ 285 .insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::ENUM_LITERAL)}) 286 .first->second; 287 } 288 case DeclType::INTERFACE: { 289 return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)}) 290 .first->second; 291 } 292 case DeclType::CLASS: { 293 return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::CLASS)}) 294 .first->second; 295 } 296 case DeclType::TYPE_PARAMETER: { 297 return bindings_ 298 .insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::TYPE_PARAMETER)}) 299 .first->second; 300 } 301 case DeclType::FUNC: { 302 flags = VariableFlags::HOIST; 303 [[fallthrough]]; 304 } 305 default: { 306 if (currentVariable != nullptr) { 307 return nullptr; 308 } 309 310 auto [_, shadowed] = IterateShadowedVariables( 311 newDecl->Name(), [](const Variable *v) { return v->HasFlag(VariableFlags::LEXICAL_VAR); }); 312 (void)_; 313 314 if (shadowed) { 315 return nullptr; 316 } 317 318 return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)}).first->second; 319 } 320 } 321} 322 323void VariableScope::CheckDirectEval(public_lib::Context *context) 324{ 325 ASSERT(context); 326 const auto &varMap = Bindings(); 327 328 if (!HasFlag(ScopeFlags::NO_REG_STORE) || varMap.empty()) { 329 evalBindings_ = compiler::INVALID_LITERAL_BUFFER_ID; 330 return; 331 } 332 333 size_t constBindings = 0; 334 for (const auto &[name, var] : varMap) { 335 (void)name; 336 var->SetLexical(this); 337 338 if (var->LexicalBound() && var->Declaration()->IsConstDecl()) { 339 constBindings++; 340 } 341 } 342 343 std::vector<compiler::Literal> literals(LexicalSlots() + constBindings, compiler::Literal(util::StringView())); 344 345 if (constBindings == 0U) { 346 for (const auto &[name, variable] : varMap) { 347 if (!variable->LexicalBound()) { 348 continue; 349 } 350 351 literals[variable->AsLocalVariable()->LexIdx()] = compiler::Literal(name); 352 } 353 } else { 354 std::vector<varbinder::Variable *> bindings(LexicalSlots()); 355 356 for (const auto &[name, variable] : varMap) { 357 (void)name; 358 if (!variable->LexicalBound()) { 359 continue; 360 } 361 362 bindings[variable->AsLocalVariable()->LexIdx()] = variable; 363 } 364 365 uint32_t buffIndex = 0; 366 for (const auto *variable : bindings) { 367 if (variable == nullptr) { 368 ASSERT(literals[buffIndex].GetString().empty()); 369 buffIndex++; 370 continue; 371 } 372 if (variable->Declaration()->IsConstDecl()) { 373 literals[buffIndex++] = compiler::Literal(true); 374 } 375 literals[buffIndex++] = compiler::Literal(variable->Name()); 376 } 377 } 378 context->contextLiterals.emplace_back(literals); 379 evalBindings_ = context->contextLiterals.size() - 1; 380} 381 382Variable *ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags) 383{ 384 ASSERT(newDecl->IsParameterDecl()); 385 386 if (currentVariable != nullptr) { 387 return nullptr; 388 } 389 390 auto *param = allocator->New<LocalVariable>(newDecl, flags); 391 param->SetScope(this); 392 393 params_.push_back(param); 394 InsertBinding(newDecl->Name(), param); 395 return param; 396} 397 398std::tuple<ParameterDecl *, ir::AstNode *, Variable *> ParamScope::AddParamDecl(ArenaAllocator *allocator, 399 ir::AstNode *param) 400{ 401 const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size()); 402 403 auto *decl = NewDecl<ParameterDecl>(allocator, name); 404 auto *var = AddParam(allocator, FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS), decl, 405 VariableFlags::VAR | VariableFlags::LOCAL); 406 407 if (var == nullptr) { 408 return {decl, param, nullptr}; 409 } 410 411 if (!pattern) { 412 decl->BindNode(param); 413 return {decl, nullptr, var}; 414 } 415 416 std::vector<ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param); 417 418 for (auto *binding : bindings) { 419 auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name()); 420 varDecl->BindNode(binding); 421 422 if (FindLocal(varDecl->Name(), varbinder::ResolveBindingOptions::BINDINGS) != nullptr) { 423 return {decl, binding, nullptr}; 424 } 425 426 auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR | VariableFlags::LOCAL); 427 TryInsertBinding(varDecl->Name(), paramVar); 428 } 429 430 return {decl, nullptr, var}; 431} 432 433void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name) 434{ 435 nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED); 436 if (!functionScope_->InsertBinding(name, nameVar_).second) { 437 nameVar_ = nullptr; 438 } 439} 440 441Variable *FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator, 442 [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl, 443 [[maybe_unused]] ScriptExtension extension) 444{ 445 UNREACHABLE(); 446} 447 448Variable *FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, 449 [[maybe_unused]] ScriptExtension extension) 450{ 451 ir::Identifier *ident {}; 452 Variable *var {}; 453 switch (newDecl->Type()) { 454 case DeclType::VAR: { 455 return AddVar<LocalVariable>(allocator, currentVariable, newDecl); 456 } 457 case DeclType::FUNC: { 458 return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension); 459 } 460 case DeclType::ENUM: { 461 return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second; 462 } 463 case DeclType::ENUM_LITERAL: { 464 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL); 465 } 466 // NOTE(psiket):Duplication 467 case DeclType::INTERFACE: { 468 ident = newDecl->Node()->AsTSInterfaceDeclaration()->Id(); 469 auto interfaceVar = allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE); 470 var = InsertBinding(newDecl->Name(), interfaceVar).first->second; 471 break; 472 } 473 case DeclType::CLASS: { 474 ident = newDecl->Node()->AsClassDefinition()->Ident(); 475 auto classVar = allocator->New<LocalVariable>(newDecl, VariableFlags::CLASS); 476 var = InsertBinding(newDecl->Name(), classVar).first->second; 477 break; 478 } 479 case DeclType::TYPE_ALIAS: { 480 ident = newDecl->Node()->AsTSTypeAliasDeclaration()->Id(); 481 var = typeAliasScope_->AddBinding(allocator, currentVariable, newDecl, extension); 482 break; 483 } 484 default: { 485 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl); 486 } 487 } 488 if (var != nullptr) { 489 var->SetScope(this); 490 if (ident != nullptr) { 491 ident->SetVariable(var); 492 } 493 } 494 return var; 495} 496 497Variable *GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, 498 [[maybe_unused]] ScriptExtension extension) 499{ 500 switch (newDecl->Type()) { 501 case DeclType::VAR: { 502 return AddVar<GlobalVariable>(allocator, currentVariable, newDecl); 503 } 504 case DeclType::FUNC: { 505 return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension); 506 } 507 case DeclType::ENUM: { 508 return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second; 509 } 510 case DeclType::ENUM_LITERAL: { 511 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL); 512 } 513 case DeclType::INTERFACE: { 514 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE); 515 } 516 default: { 517 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl); 518 } 519 } 520} 521 522Scope::InsertResult GlobalScope::InsertBinding(const util::StringView &name, Variable *const var) 523{ 524 return GlobalScope::InsertImpl(name, var, false, false); 525} 526 527Scope::InsertResult GlobalScope::TryInsertBinding(const util::StringView &name, Variable *const var) 528{ 529 const auto insRes = Scope::TryInsertBinding(name, var); 530 if (insRes.second) { 531 [[maybe_unused]] const bool insertSuccess = std::get<1>(foreignBindings_.try_emplace(name, var)); 532 ASSERT(insertSuccess); 533 } 534 535 return insRes; 536} 537 538void GlobalScope::MergeBindings([[maybe_unused]] const VariableMap &bindings) 539{ 540 UNREACHABLE(); 541} 542 543Scope::VariableMap::size_type GlobalScope::EraseBinding(const util::StringView &name) 544{ 545 const auto erased = Scope::EraseBinding(name); 546 if (erased != 0) { 547 [[maybe_unused]] const auto erasedForeign = foreignBindings_.erase(name); 548 ASSERT(erasedForeign != 0); 549 } 550 551 return erased; 552} 553 554Scope::InsertResult GlobalScope::InsertForeignBinding(const util::StringView &name, Variable *const var) 555{ 556 return GlobalScope::InsertImpl(name, var, true, false); 557} 558 559Scope::InsertResult GlobalScope::InsertImpl(const util::StringView &name, Variable *const var, const bool isForeign, 560 const bool isDynamic) 561{ 562 if (!isDynamic && isForeign && !var->Declaration()->Name().Is(compiler::Signatures::ETS_GLOBAL)) { 563 const auto *const node = var->Declaration()->Node(); 564 565 if (!(node->IsExported() || node->IsDefaultExported() || node->IsExportedType())) { 566 return Scope::InsertResult {Bindings().end(), false}; 567 } 568 } 569 570 const auto insRes = Scope::InsertBinding(name, var); 571 if (insRes.second) { 572 [[maybe_unused]] const bool insertSuccess = std::get<1>(foreignBindings_.emplace(name, isForeign)); 573 ASSERT(insertSuccess); 574 } 575 576 return insRes; 577} 578 579bool GlobalScope::IsForeignBinding(const util::StringView &name) const 580{ 581 // Asserts make sure that the passed in key comes from this scope 582 ASSERT(Bindings().find(name) != Bindings().end()); 583 ASSERT(foreignBindings_.find(name) != foreignBindings_.end()); 584 585 return foreignBindings_.at(name); 586} 587 588Scope::InsertResult GlobalScope::InsertDynamicBinding(const util::StringView &name, Variable *const var) 589{ 590 return InsertImpl(name, var, true, true); 591} 592 593// ModuleScope 594 595Variable *ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, 596 [[maybe_unused]] ScriptExtension extension) 597{ 598 switch (newDecl->Type()) { 599 case DeclType::VAR: { 600 return AddVar<LocalVariable>(allocator, currentVariable, newDecl); 601 } 602 case DeclType::FUNC: { 603 return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension); 604 } 605 case DeclType::ENUM: { 606 return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second; 607 } 608 case DeclType::ENUM_LITERAL: { 609 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL); 610 } 611 case DeclType::INTERFACE: { 612 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE); 613 } 614 case DeclType::IMPORT: { 615 return AddImport(allocator, currentVariable, newDecl); 616 } 617 case DeclType::EXPORT: { 618 return allocator->New<LocalVariable>(newDecl, VariableFlags::NONE); 619 } 620 default: { 621 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl); 622 } 623 } 624} 625 626void ModuleScope::AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls) 627{ 628 auto res = imports_.emplace_back(importDecl, decls); 629 630 for (auto &decl : res.second) { 631 decl->BindNode(importDecl); 632 } 633} 634 635void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl) 636{ 637 decl->BindNode(exportDecl); 638 639 ArenaVector<ExportDecl *> decls(allocator_->Adapter()); 640 decls.push_back(decl); 641 642 AddExportDecl(exportDecl, std::move(decls)); 643} 644 645void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls) 646{ 647 auto res = exports_.emplace_back(exportDecl, decls); 648 649 for (auto &decl : res.second) { 650 decl->BindNode(exportDecl); 651 } 652} 653 654Variable *ModuleScope::AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) 655{ 656 if (currentVariable != nullptr && currentVariable->Declaration()->Type() != DeclType::VAR) { 657 return nullptr; 658 } 659 660 if (newDecl->Node()->IsImportNamespaceSpecifier()) { 661 return InsertBinding(newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::READONLY)) 662 .first->second; 663 } 664 665 auto *variable = allocator->New<ModuleVariable>(newDecl, VariableFlags::NONE); 666 variable->ExoticName() = newDecl->AsImportDecl()->ImportName(); 667 InsertBinding(newDecl->Name(), variable); 668 return variable; 669} 670 671bool ModuleScope::ExportAnalysis() 672{ 673 std::set<util::StringView> exportedNames; 674 675 for (const auto &[exportDecl, decls] : exports_) { 676 if (exportDecl->IsExportAllDeclaration()) { 677 const auto *exportAllDecl = exportDecl->AsExportAllDeclaration(); 678 679 if (exportAllDecl->Exported() == nullptr) { 680 continue; 681 } 682 683 auto result = exportedNames.insert(exportAllDecl->Exported()->Name()); 684 if (!result.second) { 685 return false; 686 } 687 688 continue; 689 } 690 691 if (exportDecl->IsExportNamedDeclaration()) { 692 const auto *exportNamedDecl = exportDecl->AsExportNamedDeclaration(); 693 694 if (exportNamedDecl->Source() != nullptr) { 695 continue; 696 } 697 } 698 699 for (const auto *decl : decls) { 700 varbinder::Variable *variable = FindLocal(decl->LocalName(), varbinder::ResolveBindingOptions::BINDINGS); 701 702 if (variable == nullptr) { 703 continue; 704 } 705 706 auto result = exportedNames.insert(decl->ExportName()); 707 if (!result.second) { 708 return false; 709 } 710 711 if (!variable->IsModuleVariable()) { 712 variable->AddFlag(VariableFlags::LOCAL_EXPORT); 713 localExports_.insert({variable, decl->ExportName()}); 714 } 715 } 716 } 717 718 return true; 719} 720 721Variable *FunctionScope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const 722{ 723 if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) { 724 auto found = typeAliasScope_->Bindings().find(name); 725 if (found != typeAliasScope_->Bindings().end()) { 726 return found->second; 727 } 728 } 729 730 if ((options & ResolveBindingOptions::ALL_NON_TYPE) == 0) { 731 return nullptr; 732 } 733 734 if ((options & ResolveBindingOptions::INTERFACES) != 0) { 735 std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name); 736 util::StringView interfaceNameView(tsBindingName); 737 738 auto res = Bindings().find(interfaceNameView); 739 if (res != Bindings().end()) { 740 return res->second; 741 } 742 743 if ((options & ResolveBindingOptions::BINDINGS) == 0) { 744 return nullptr; 745 } 746 } 747 748 auto res = Bindings().find(name); 749 if (res == Bindings().end()) { 750 return nullptr; 751 } 752 753 return res->second; 754} 755 756// LocalScope 757 758Variable *LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, 759 [[maybe_unused]] ScriptExtension extension) 760{ 761 return AddLocal(allocator, currentVariable, newDecl, extension); 762} 763 764Variable *LocalScopeWithTypeAlias::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, 765 [[maybe_unused]] ScriptExtension extension) 766{ 767 if (newDecl->IsTypeAliasDecl()) { 768 auto *ident = newDecl->Node()->AsTSTypeAliasDeclaration()->Id(); 769 auto *var = typeAliasScope_->AddBinding(allocator, currentVariable, newDecl, extension); 770 if (var != nullptr) { 771 var->SetScope(this); 772 if (ident != nullptr) { 773 ident->SetVariable(var); 774 } 775 } 776 return var; 777 } 778 return AddLocal(allocator, currentVariable, newDecl, extension); 779} 780 781Variable *LocalScopeWithTypeAlias::FindLocal(const util::StringView &name, ResolveBindingOptions options) const 782{ 783 if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) { 784 auto found = typeAliasScope_->Bindings().find(name); 785 if (found != typeAliasScope_->Bindings().end()) { 786 return found->second; 787 } 788 } 789 790 if ((options & ResolveBindingOptions::ALL_NON_TYPE) == 0) { 791 return nullptr; 792 } 793 794 if ((options & ResolveBindingOptions::INTERFACES) != 0) { 795 std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name); 796 util::StringView interfaceNameView(tsBindingName); 797 798 auto res = Bindings().find(interfaceNameView); 799 if (res != Bindings().end()) { 800 return res->second; 801 } 802 803 if ((options & ResolveBindingOptions::BINDINGS) == 0) { 804 return nullptr; 805 } 806 } 807 808 auto res = Bindings().find(name); 809 if (res == Bindings().end()) { 810 return nullptr; 811 } 812 813 return res->second; 814} 815 816Variable *ClassScope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const 817{ 818 if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) { 819 auto found = TypeAliasScope()->Bindings().find(name); 820 if (found != TypeAliasScope()->Bindings().end()) { 821 return found->second; 822 } 823 } 824 825 if ((options & ResolveBindingOptions::VARIABLES) != 0) { 826 auto found = instanceFieldScope_->Bindings().find(name); 827 if (found != instanceFieldScope_->Bindings().end()) { 828 return found->second; 829 } 830 } 831 832 if ((options & ResolveBindingOptions::STATIC_VARIABLES) != 0) { 833 auto found = staticFieldScope_->Bindings().find(name); 834 if (found != staticFieldScope_->Bindings().end()) { 835 return found->second; 836 } 837 } 838 839 if ((options & ResolveBindingOptions::DECLARATION) != 0) { 840 auto found = instanceDeclScope_->Bindings().find(name); 841 if (found != instanceDeclScope_->Bindings().end()) { 842 return found->second; 843 } 844 } 845 846 if ((options & ResolveBindingOptions::STATIC_DECLARATION) != 0) { 847 auto found = staticDeclScope_->Bindings().find(name); 848 if (found != staticDeclScope_->Bindings().end()) { 849 return found->second; 850 } 851 } 852 853 if ((options & ResolveBindingOptions::METHODS) != 0) { 854 auto found = instanceMethodScope_->Bindings().find(name); 855 if (found != instanceMethodScope_->Bindings().end()) { 856 return found->second; 857 } 858 } 859 860 if ((options & ResolveBindingOptions::STATIC_METHODS) != 0) { 861 auto found = staticMethodScope_->Bindings().find(name); 862 if (found != staticMethodScope_->Bindings().end()) { 863 return found->second; 864 } 865 } 866 867 return nullptr; 868} 869 870void ClassScope::SetBindingProps(Decl *newDecl, BindingProps *props, bool isStatic) 871{ 872 switch (newDecl->Type()) { 873 case DeclType::CONST: 874 case DeclType::READONLY: 875 case DeclType::LET: { 876 props->SetBindingProps(VariableFlags::PROPERTY, newDecl->Node()->AsClassProperty()->Id(), 877 isStatic ? staticFieldScope_ : instanceFieldScope_); 878 break; 879 } 880 case DeclType::INTERFACE: { 881 props->SetBindingProps(VariableFlags::INTERFACE, newDecl->Node()->AsTSInterfaceDeclaration()->Id(), 882 isStatic ? staticDeclScope_ : instanceDeclScope_); 883 break; 884 } 885 case DeclType::CLASS: { 886 props->SetBindingProps(VariableFlags::CLASS, newDecl->Node()->AsClassDefinition()->Ident(), 887 isStatic ? staticDeclScope_ : instanceDeclScope_); 888 break; 889 } 890 case DeclType::ENUM_LITERAL: { 891 props->SetBindingProps(VariableFlags::ENUM_LITERAL, newDecl->Node()->AsTSEnumDeclaration()->Key(), 892 isStatic ? staticDeclScope_ : instanceDeclScope_); 893 break; 894 } 895 case DeclType::TYPE_ALIAS: { 896 props->SetBindingProps(VariableFlags::TYPE_ALIAS, newDecl->Node()->AsTSTypeAliasDeclaration()->Id(), 897 TypeAliasScope()); 898 break; 899 } 900 default: { 901 UNREACHABLE(); 902 break; 903 } 904 } 905} 906 907Variable *ClassScope::AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl, 908 [[maybe_unused]] ScriptExtension extension) 909{ 910 bool isStatic = newDecl->Node()->IsStatic(); 911 BindingProps props; 912 913 if (isStatic) { 914 props.SetFlagsType(VariableFlags::STATIC); 915 } 916 917 SetBindingProps(newDecl, &props, isStatic); 918 919 auto options = newDecl->Type() != DeclType::TYPE_ALIAS ? ResolveBindingOptions::ALL_NON_TYPE 920 : ResolveBindingOptions::TYPE_ALIASES; 921 922 const auto *foundVar = FindLocal(newDecl->Name(), options); 923 if (foundVar != nullptr) { 924 if (!newDecl->IsLetOrConstDecl()) { 925 return nullptr; 926 } 927 928 foundVar = FindLocal(newDecl->Name(), 929 ResolveBindingOptions::ALL ^ (isStatic ? ResolveBindingOptions::VARIABLES 930 : ResolveBindingOptions::STATIC_VARIABLES)); 931 if (foundVar != nullptr) { 932 return nullptr; 933 } 934 } 935 936 auto *var = props.GetTargetScope()->AddBinding(allocator, nullptr, newDecl, extension); 937 if (var == nullptr) { 938 return nullptr; 939 } 940 941 if (auto node = newDecl->Node(); 942 node->IsStatement() && 943 (node->AsStatement()->IsMethodDefinition() || node->IsClassProperty() || node->IsClassStaticBlock()) && 944 node->AsStatement()->AsClassElement()->Value() != nullptr) { 945 props.SetFlagsType(VariableFlags::INITIALIZED); 946 } 947 948 var->SetScope(this); 949 var->AddFlag(props.GetFlags()); 950 951 if (props.GetIdent() != nullptr) { 952 props.GetIdent()->SetVariable(var); 953 } 954 955 return var; 956} 957 958void LoopDeclarationScope::ConvertToVariableScope(ArenaAllocator *allocator) 959{ 960 if (NeedLexEnv()) { 961 return; 962 } 963 964 const auto &bindings = Bindings(); 965 for (auto &[name, var] : bindings) { 966 if (!var->LexicalBound() || !var->Declaration()->IsLetOrConstDecl()) { 967 continue; 968 } 969 970 slotIndex_++; 971 loopType_ = ScopeType::LOOP_DECL; 972 auto *copiedVar = var->AsLocalVariable()->Copy(allocator, var->Declaration()); 973 copiedVar->AddFlag(VariableFlags::INITIALIZED | VariableFlags::PER_ITERATION); 974 var->AddFlag(VariableFlags::LOOP_DECL); 975 loopScope_->InsertBinding(name, copiedVar); 976 } 977 978 if (loopType_ == ScopeType::LOOP_DECL) { 979 auto *parentVarScope = Parent()->EnclosingVariableScope(); 980 slotIndex_ = std::max(slotIndex_, parentVarScope->LexicalSlots()); 981 evalBindings_ = parentVarScope->EvalBindings(); 982 initScope_ = allocator->New<LocalScope>(allocator, Parent()); 983 initScope_->BindNode(Node()); 984 initScope_->MergeBindings(bindings); 985 } 986} 987 988void LoopScope::ConvertToVariableScope(ArenaAllocator *allocator) 989{ 990 declScope_->ConvertToVariableScope(allocator); 991 992 if (loopType_ != ScopeType::LOCAL) { 993 return; 994 } 995 996 for (const auto &[_, var] : Bindings()) { 997 (void)_; 998 if (var->LexicalBound() && var->Declaration()->IsLetDecl()) { 999 ASSERT(declScope_->NeedLexEnv()); 1000 loopType_ = ScopeType::LOOP; 1001 break; 1002 } 1003 } 1004 1005 if (loopType_ == ScopeType::LOOP) { 1006 slotIndex_ = std::max(slotIndex_, declScope_->LexicalSlots()); 1007 evalBindings_ = declScope_->EvalBindings(); 1008 } 1009} 1010 1011Variable *CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, 1012 [[maybe_unused]] ScriptExtension extension) 1013{ 1014 return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED); 1015} 1016 1017Variable *CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, 1018 [[maybe_unused]] ScriptExtension extension) 1019{ 1020 if (!newDecl->IsVarDecl() && 1021 (paramScope_->FindLocal(newDecl->Name(), varbinder::ResolveBindingOptions::BINDINGS) != nullptr)) { 1022 return nullptr; 1023 } 1024 1025 if (newDecl->IsTypeAliasDecl()) { 1026 auto *ident = newDecl->Node()->AsTSTypeAliasDeclaration()->Id(); 1027 auto *var = TypeAliasScope()->AddBinding(allocator, currentVariable, newDecl, extension); 1028 if (var != nullptr) { 1029 var->SetScope(this); 1030 if (ident != nullptr) { 1031 ident->SetVariable(var); 1032 } 1033 } 1034 return var; 1035 } 1036 1037 return AddLocal(allocator, currentVariable, newDecl, extension); 1038} 1039} // namespace ark::es2panda::varbinder 1040