• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-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 "util.h"
17 
18 #include "compiler/lowering/scopesInit/scopesInitPhase.h"
19 #include "ir/expressions/identifier.h"
20 
21 namespace ark::es2panda::compiler {
22 
NearestScope(const ir::AstNode * ast)23 varbinder::Scope *NearestScope(const ir::AstNode *ast)
24 {
25     while (ast != nullptr && !ast->IsScopeBearer()) {
26         ast = ast->Parent();
27     }
28 
29     return ast == nullptr ? nullptr : ast->Scope();
30 }
31 
ContainingClass(const ir::AstNode * ast)32 checker::ETSObjectType const *ContainingClass(const ir::AstNode *ast)
33 {
34     while (ast != nullptr && !ast->IsClassDefinition()) {
35         ast = ast->Parent();
36     }
37 
38     return ast == nullptr ? nullptr : ast->AsClassDefinition()->TsType()->AsETSObjectType();
39 }
40 
Gensym(ArenaAllocator * const allocator)41 ir::Identifier *Gensym(ArenaAllocator *const allocator)
42 {
43     util::UString const s = GenName(allocator);
44     return allocator->New<ir::Identifier>(s.View(), allocator);
45 }
46 
GenName(ArenaAllocator * const allocator)47 util::UString GenName(ArenaAllocator *const allocator)
48 {
49     static std::string const GENSYM_CORE = "gensym%%_";
50     static std::size_t gensymCounter = 0U;
51 
52     return util::UString {GENSYM_CORE + std::to_string(++gensymCounter), allocator};
53 }
54 
55 // Function to clear expression node types and identifier node variables (for correct re-binding and re-checking)
ClearTypesVariablesAndScopes(ir::AstNode * node)56 void ClearTypesVariablesAndScopes(ir::AstNode *node) noexcept
57 {
58     auto doNode = [](ir::AstNode *nn) {
59         if (nn->IsScopeBearer()) {
60             nn->ClearScope();
61         }
62         if (nn->IsTyped() && !(nn->IsExpression() && nn->AsExpression()->IsTypeNode())) {
63             nn->AsTyped()->SetTsType(nullptr);
64         }
65         if (nn->IsIdentifier()) {
66             nn->AsIdentifier()->SetVariable(nullptr);
67         }
68     };
69 
70     doNode(node);
71     node->IterateRecursively(doNode);
72 }
73 
FindCaptured(ArenaAllocator * allocator,ir::AstNode * scopeBearer)74 ArenaSet<varbinder::Variable *> FindCaptured(ArenaAllocator *allocator, ir::AstNode *scopeBearer) noexcept
75 {
76     auto result = ArenaSet<varbinder::Variable *> {allocator->Adapter()};
77     auto scopes = ArenaSet<varbinder::Scope *> {allocator->Adapter()};
78     scopeBearer->IterateRecursivelyPreorder([&result, &scopes](ir::AstNode *ast) {
79         if (ast->IsScopeBearer() && ast->Scope() != nullptr) {
80             scopes.insert(ast->Scope());
81             if (ast->Scope()->IsFunctionScope()) {
82                 scopes.insert(ast->Scope()->AsFunctionScope()->ParamScope());
83             } else if (ast->IsForUpdateStatement() || ast->IsForInStatement() || ast->IsForOfStatement() ||
84                        ast->IsCatchClause()) {
85                 // NOTE(gogabr) LoopScope _does not_ currently respond to IsLoopScope().
86                 // For now, this is the way to reach LoopDeclarationScope.
87                 scopes.insert(ast->Scope()->Parent());
88             }
89         }
90         if (ast->IsIdentifier()) {
91             auto *var = ast->AsIdentifier()->Variable();
92             if (var == nullptr || !var->HasFlag(varbinder::VariableFlags::LOCAL)) {
93                 return;
94             }
95             auto *sc = var->GetScope();
96             if (sc != nullptr && !sc->IsClassScope() && !sc->IsGlobalScope() && scopes.count(var->GetScope()) == 0) {
97                 result.insert(var);
98             }
99         }
100     });
101     return result;
102 }
103 
104 // Rerun varbinder and checker on the node.
Recheck(varbinder::ETSBinder * varBinder,checker::ETSChecker * checker,ir::AstNode * node)105 void Recheck(varbinder::ETSBinder *varBinder, checker::ETSChecker *checker, ir::AstNode *node)
106 {
107     auto *scope = NearestScope(node->Parent());
108     auto bscope = varbinder::LexicalScope<varbinder::Scope>::Enter(varBinder, scope);
109 
110     ClearTypesVariablesAndScopes(node);
111     InitScopesPhaseETS::RunExternalNode(node, varBinder);
112     varBinder->ResolveReferencesForScopeWithContext(node, scope);
113 
114     auto *containingClass = ContainingClass(node);
115     // NOTE(gogabr: should determine checker status more finely.
116     auto checkerCtx = checker::SavedCheckerContext(
117         checker, (containingClass == nullptr) ? checker::CheckerStatus::NO_OPTS : checker::CheckerStatus::IN_CLASS,
118         containingClass);
119     auto scopeCtx = checker::ScopeContext(checker, scope);
120 
121     node->Check(checker);
122 }
123 
124 // Note: run varbinder and checker on the new node generated in lowering phases
CheckLoweredNode(varbinder::ETSBinder * varBinder,checker::ETSChecker * checker,ir::AstNode * node)125 void CheckLoweredNode(varbinder::ETSBinder *varBinder, checker::ETSChecker *checker, ir::AstNode *node)
126 {
127     InitScopesPhaseETS::RunExternalNode(node, varBinder);
128     auto *scope = NearestScope(node);
129     varBinder->ResolveReferencesForScopeWithContext(node, scope);
130 
131     auto *containingClass = ContainingClass(node);
132     auto checkerCtx = checker::SavedCheckerContext(
133         checker, (containingClass == nullptr) ? checker::CheckerStatus::NO_OPTS : checker::CheckerStatus::IN_CLASS,
134         containingClass);
135     auto scopeCtx = checker::ScopeContext(checker, scope);
136 
137     node->Check(checker);
138 }
139 
140 }  // namespace ark::es2panda::compiler
141