• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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