1/** 2 * Copyright (c) 2021 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 "hoisting.h" 17 18#include <binder/binder.h> 19#include <binder/scope.h> 20#include <compiler/core/pandagen.h> 21#include <ir/base/scriptFunction.h> 22#include <ir/statements/variableDeclaration.h> 23#include <parser/module/sourceTextModuleRecord.h> 24 25namespace panda::es2panda::compiler { 26 27static void StoreModuleVarOrLocalVar(PandaGen *pg, binder::ScopeFindResult &result, const binder::Decl *decl) 28{ 29 if (decl->IsImportOrExportDecl()) { 30 ASSERT(pg->Scope()->IsModuleScope()); 31 auto *var = pg->Scope()->FindLocal(decl->Name()); 32 CHECK_NOT_NULL(var); 33 ASSERT(var->IsModuleVariable()); 34 pg->StoreModuleVariable(decl->Node(), var->AsModuleVariable()); 35 } else { 36 pg->StoreAccToLexEnv(decl->Node(), result, true); 37 } 38} 39 40static void HoistVar(PandaGen *pg, binder::Variable *var, const binder::VarDecl *decl) 41{ 42 if (decl->IsDeclare()) { 43 return; 44 } 45 46 auto *scope = pg->Scope(); 47 if (scope->IsGlobalScope()) { 48 pg->LoadConst(decl->Node(), Constant::JS_UNDEFINED); 49 pg->StoreGlobalVar(decl->Node(), decl->Name()); 50 return; 51 } 52 53 auto *funcScope = scope->EnclosingFunctionVariableScope(); 54 CHECK_NOT_NULL(funcScope); 55 if (scope->HasParamScope() && funcScope->ParamScope()->HasParam(decl->Name())) { 56 return; 57 } 58 59 binder::ScopeFindResult result(decl->Name(), scope, 0, var); 60 61 pg->LoadConst(decl->Node(), Constant::JS_UNDEFINED); 62 StoreModuleVarOrLocalVar(pg, result, decl); 63} 64 65static void HoistFunction(PandaGen *pg, binder::Variable *var, const binder::FunctionDecl *decl) 66{ 67 const ir::ScriptFunction *scriptFunction = decl->Node()->AsScriptFunction(); 68 if (scriptFunction->Declare()) { 69 return; 70 } 71 72 const auto &internalName = scriptFunction->Scope()->InternalName(); 73 auto *scope = pg->Scope(); 74 if (scope->IsGlobalScope()) { 75 pg->DefineFunction(decl->Node(), scriptFunction, internalName); 76 pg->StoreGlobalVar(decl->Node(), var->Declaration()->Name()); 77 return; 78 } 79 80 ASSERT(scope->IsFunctionScope() || scope->IsCatchScope() || scope->IsLocalScope() || 81 scope->IsModuleScope() || scope->IsTSModuleScope() || scope->IsTSEnumScope() || 82 scope->IsStaticBlockScope()); 83 binder::ScopeFindResult result(decl->Name(), scope, 0, var); 84 85 pg->DefineFunction(decl->Node(), scriptFunction, internalName); 86 StoreModuleVarOrLocalVar(pg, result, decl); 87} 88 89static void HoistNameSpaceImports(PandaGen *pg) 90{ 91 if (pg->Scope()->IsModuleScope()) { 92 parser::SourceTextModuleRecord *moduleRecord = pg->Binder()->Program()->ModuleRecord(); 93 ASSERT(moduleRecord != nullptr); 94 for (auto nameSpaceEntry : moduleRecord->GetNamespaceImportEntries()) { 95 auto *var = pg->TopScope()->FindLocal(nameSpaceEntry->localName_); 96 CHECK_NOT_NULL(var); 97 auto *node = var->Declaration()->Node(); 98 CHECK_NOT_NULL(node); 99 pg->GetModuleNamespace(node, nameSpaceEntry->moduleRequestIdx_); 100 pg->StoreVar(node, {nameSpaceEntry->localName_, pg->TopScope(), 0, var}, true); 101 } 102 } 103} 104 105void Hoisting::Hoist(PandaGen *pg) 106{ 107 const auto *scope = pg->Scope(); 108 109 for (const auto &[_, var] : scope->Bindings()) { 110 (void)_; 111 if (!var->HasFlag(binder::VariableFlags::HOIST)) { 112 continue; 113 } 114 115 const auto *decl = var->Declaration(); 116 117 if (decl->IsVarDecl()) { 118 HoistVar(pg, var, decl->AsVarDecl()); 119 } else { 120 ASSERT(decl->IsFunctionDecl()); 121 HoistFunction(pg, var, decl->AsFunctionDecl()); 122 } 123 } 124 125 HoistNameSpaceImports(pg); 126} 127 128} // namespace panda::es2panda::compiler 129