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