• 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 "scope.h"
17 
18 #include <binder/declaration.h>
19 #include <util/helpers.h>
20 #include <binder/tsBinding.h>
21 #include <binder/variable.h>
22 #include <binder/variableFlags.h>
23 #include <ir/astNode.h>
24 #include <ir/base/scriptFunction.h>
25 #include <ir/expressions/identifier.h>
26 #include <ir/module/exportAllDeclaration.h>
27 #include <ir/module/exportNamedDeclaration.h>
28 #include <ir/module/exportSpecifier.h>
29 #include <ir/module/importDeclaration.h>
30 #include <macros.h>
31 #include <util/concurrent.h>
32 #include <util/ustring.h>
33 
34 #include <algorithm>
35 #include <sstream>
36 
37 namespace panda::es2panda::binder {
38 
EnclosingVariableScope()39 VariableScope *Scope::EnclosingVariableScope()
40 {
41     Scope *iter = this;
42 
43     while (iter) {
44         if (iter->IsVariableScope()) {
45             return iter->AsVariableScope();
46         }
47 
48         iter = iter->Parent();
49     }
50 
51     return nullptr;
52 }
53 
EnclosingFunctionVariableScope()54 FunctionScope *Scope::EnclosingFunctionVariableScope()
55 {
56     Scope *iter = this;
57     while (iter) {
58         if (iter->IsFunctionVariableScope()) {
59             return iter->AsFunctionVariableScope();
60         }
61 
62         iter = iter->Parent();
63     }
64 
65     return nullptr;
66 }
67 
FindLocal(const util::StringView & name,ResolveBindingOptions options) const68 Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
69 {
70     if (options & ResolveBindingOptions::INTERFACES) {
71         const std::string &interfaceName = binder::TSBinding::ToTSBinding(name);
72 
73         auto res = bindings_.find(util::StringView{interfaceName});
74         if (res != bindings_.end()) {
75             return res->second;
76         }
77 
78         if (!(options & ResolveBindingOptions::BINDINGS)) {
79             return nullptr;
80         }
81     }
82 
83     auto res = bindings_.find(name);
84     if (res == bindings_.end()) {
85         return nullptr;
86     }
87 
88     return res->second;
89 }
90 
HasLexEnvInCorrespondingFunctionScope(const FunctionParamScope * scope) const91 bool Scope::HasLexEnvInCorrespondingFunctionScope(const FunctionParamScope *scope) const
92 {
93     auto *funcVariableScope = scope->GetFunctionScope();
94     // we may only have function param scope without function scope in TS here
95     if ((funcVariableScope != nullptr) && (funcVariableScope->NeedLexEnv())) {
96         return true;
97     }
98     return false;
99 }
100 
Find(const util::StringView & name,ResolveBindingOptions options) const101 ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions options) const
102 {
103     uint32_t level = 0;
104     uint32_t lexLevel = 0;
105     const auto *iter = this;
106     bool crossConcurrent = false;
107     // If the first scope is functionParamScope, it means its corresponding functionScope is not
108     // iterated. so by default we set prevScopeNotFunctionScope as true so under such case,
109     // functionScopeNotIterated will be true.
110     bool prevScopeNotFunctionScope = true;
111     bool lexical = false;
112 
113     while (iter != nullptr) {
114         bool functionScopeNotIterated = iter->IsFunctionParamScope() && prevScopeNotFunctionScope;
115         Variable *v = iter->FindLocal(name, options);
116 
117         if (v != nullptr) {
118             return {name, const_cast<Scope *>(iter), level, lexLevel, v, crossConcurrent};
119         }
120 
121         if (iter->IsFunctionVariableScope() && !lexical) {
122             lexical = true;
123         }
124 
125         if (iter->IsVariableScope()) {
126             if (lexical) {
127                 level++;
128             }
129 
130             if (iter->IsFunctionScope() && !crossConcurrent) {
131                 crossConcurrent = iter->Node()->AsScriptFunction()->IsConcurrent() ? true : false;
132             }
133             if (iter->AsVariableScope()->NeedLexEnv()) {
134                 lexLevel++;
135             }
136         } else if (functionScopeNotIterated) {
137             level++;
138             if (HasLexEnvInCorrespondingFunctionScope(iter->AsFunctionParamScope())) {
139                 lexLevel++;
140             }
141         }
142         prevScopeNotFunctionScope = !iter->IsFunctionVariableScope();
143         iter = iter->Parent();
144     }
145 
146     return {name, nullptr, 0, 0, nullptr, crossConcurrent};
147 }
148 
FindDecl(const util::StringView & name) const149 Decl *Scope::FindDecl(const util::StringView &name) const
150 {
151     for (auto *it : decls_) {
152         if (it->Name() == name) {
153             return it;
154         }
155     }
156 
157     return nullptr;
158 }
159 
HasVarDecl(const util::StringView & name) const160 bool Scope::HasVarDecl(const util::StringView &name) const
161 {
162     for (auto *it : decls_) {
163         if (it->Name() == name && it->IsVarDecl()) {
164             return true;
165         }
166     }
167 
168     return false;
169 }
170 
IterateShadowedVariables(const util::StringView & name,const VariableVisitior & visitor)171 std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor)
172 {
173     auto *iter = this;
174 
175     while (true) {
176         auto *v = iter->FindLocal(name);
177 
178         if (v && visitor(v)) {
179             return {iter, true};
180         }
181 
182         if (iter->IsFunctionVariableScope()) {
183             break;
184         }
185 
186         iter = iter->Parent();
187     }
188 
189     return {iter, false};
190 }
191 
AddLocal(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)192 bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
193                      [[maybe_unused]] ScriptExtension extension)
194 {
195     VariableFlags flags = VariableFlags::NONE;
196     switch (newDecl->Type()) {
197         case DeclType::VAR: {
198             auto [scope, shadowed] = IterateShadowedVariables(
199                 newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
200 
201             if (shadowed) {
202                 return false;
203             }
204 
205             VariableFlags varFlags = VariableFlags::HOIST_VAR;
206             if (scope->IsGlobalScope()) {
207                 scope->Bindings().insert({newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)});
208             } else {
209                 scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags);
210             }
211 
212             return true;
213         }
214         case DeclType::ENUM_LITERAL: {
215             return tsBindings_.AddTSVariable<TSBindingType::ENUMLITERAL>(
216                 newDecl->Name(), allocator->New<EnumLiteralVariable>(newDecl, VariableFlags::ENUM_LITERAL));
217         }
218         case DeclType::INTERFACE: {
219             bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)});
220             return true;
221         }
222         case DeclType::FUNC: {
223             flags = VariableFlags::HOIST;
224             [[fallthrough]];
225         }
226         default: {
227             if (currentVariable) {
228                 return false;
229             }
230 
231             if (HasVarDecl(newDecl->Name())) {
232                 return false;
233             }
234 
235             bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)});
236             return true;
237         }
238     }
239 }
240 
AddParam(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,VariableFlags flags)241 bool ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)
242 {
243     ASSERT(newDecl->IsParameterDecl());
244 
245     if (currentVariable) {
246         return false;
247     }
248 
249     auto *param = allocator->New<LocalVariable>(newDecl, flags);
250 
251     params_.push_back(param);
252     bindings_.insert({newDecl->Name(), param});
253     return true;
254 }
255 
AddParamDecl(ArenaAllocator * allocator,const ir::AstNode * param)256 std::tuple<ParameterDecl *, const ir::AstNode *> ParamScope::AddParamDecl(ArenaAllocator *allocator,
257                                                                           const ir::AstNode *param)
258 {
259     const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size());
260 
261     auto *decl = NewDecl<ParameterDecl>(allocator, name);
262 
263     if (!AddParam(allocator, FindLocal(name), decl, VariableFlags::VAR)) {
264         return {decl, param};
265     }
266 
267     if (!pattern) {
268         decl->BindNode(param);
269         return {decl, nullptr};
270     }
271 
272     std::vector<const ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param);
273 
274     for (const auto *binding : bindings) {
275         auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name());
276         varDecl->BindNode(binding);
277 
278         if (FindLocal(varDecl->Name())) {
279             return {decl, binding};
280         }
281 
282         auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR);
283         bindings_.insert({varDecl->Name(), paramVar});
284     }
285 
286     return {decl, nullptr};
287 }
288 
BindName(ArenaAllocator * allocator,util::StringView name)289 void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name)
290 {
291     nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED);
292     functionScope_->Bindings().insert({name, nameVar_});
293 }
294 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)295 bool FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
296                                     [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
297                                     [[maybe_unused]] ScriptExtension extension)
298 {
299     UNREACHABLE();
300 }
301 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)302 bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
303                                [[maybe_unused]] ScriptExtension extension)
304 {
305     switch (newDecl->Type()) {
306         case DeclType::VAR: {
307             return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
308         }
309         case DeclType::FUNC: {
310             return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
311         }
312         case DeclType::CLASS: {
313             return AddClass<LocalVariable>(allocator, currentVariable, newDecl);
314         }
315         case DeclType::ENUM_LITERAL: {
316             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
317         }
318         case DeclType::NAMESPACE: {
319             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
320         }
321         case DeclType::IMPORT_EQUALS: {
322             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
323         }
324         case DeclType::INTERFACE: {
325             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
326         }
327         default: {
328             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
329         }
330     }
331 }
332 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)333 bool TSEnumScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
334                              [[maybe_unused]] ScriptExtension extension)
335 {
336     ASSERT(newDecl->Type() == DeclType::ENUM);
337     return enumMemberBindings_->insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)}).second;
338 }
339 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)340 bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
341                              [[maybe_unused]] ScriptExtension extension)
342 {
343     switch (newDecl->Type()) {
344         case DeclType::VAR: {
345             return AddVar<GlobalVariable>(allocator, currentVariable, newDecl);
346         }
347         case DeclType::FUNC: {
348             return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension);
349         }
350         case DeclType::CLASS: {
351             return AddClass<LocalVariable>(allocator, currentVariable, newDecl);
352         }
353         case DeclType::ENUM_LITERAL: {
354             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
355         }
356         case DeclType::NAMESPACE: {
357             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
358         }
359         case DeclType::IMPORT_EQUALS: {
360             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
361         }
362         case DeclType::INTERFACE: {
363             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
364         }
365         default: {
366             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
367         }
368     }
369 
370     return true;
371 }
372 
373 // ModuleScope
374 
ConvertLocalVariableToModuleVariable(ArenaAllocator * allocator,util::StringView localName)375 void ModuleScope::ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName)
376 {
377     auto res = bindings_.find(localName);
378     // Since the module's exported [localName] has been validated before,
379     // [localName] must have a binding now.
380     ASSERT(res != bindings_.end());
381     if (!res->second->IsModuleVariable()) {
382         auto *decl = res->second->Declaration();
383         decl->AddFlag(DeclarationFlags::EXPORT);
384         VariableFlags flags = res->second->Flags();
385         res->second = allocator->New<ModuleVariable>(decl, flags | VariableFlags::LOCAL_EXPORT);
386     }
387 }
388 
AssignIndexToModuleVariable(util::StringView name,uint32_t index)389 void ModuleScope::AssignIndexToModuleVariable(util::StringView name, uint32_t index)
390 {
391     auto *moduleVar = FindLocal(name);
392     ASSERT(moduleVar != nullptr);
393     ASSERT(moduleVar->IsModuleVariable());
394     moduleVar->AsModuleVariable()->AssignIndex(index);
395 }
396 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)397 bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
398                              [[maybe_unused]] ScriptExtension extension)
399 {
400     switch (newDecl->Type()) {
401         case DeclType::VAR: {
402             auto [scope, shadowed] = IterateShadowedVariables(
403                 newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
404 
405             if (shadowed) {
406                 return false;
407             }
408             return newDecl->IsImportOrExportDecl() ?
409                    AddVar<ModuleVariable>(allocator, currentVariable, newDecl) :
410                    AddVar<LocalVariable>(allocator, currentVariable, newDecl);
411         }
412         case DeclType::FUNC: {
413             if (currentVariable) {
414                 auto decl = currentVariable->Declaration();
415                 if (!decl->IsClassDecl() || !decl->AsClassDecl()->IsDeclare()) {
416                     return false;
417                 }
418             }
419             return newDecl->IsImportOrExportDecl() ?
420                    AddFunction<ModuleVariable>(allocator, currentVariable, newDecl, extension) :
421                    AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
422         }
423         case DeclType::CLASS: {
424             return newDecl->IsImportOrExportDecl() ?
425                    AddClass<ModuleVariable>(allocator, currentVariable, newDecl) :
426                    AddClass<LocalVariable>(allocator, currentVariable, newDecl);
427         }
428         case DeclType::ENUM_LITERAL: {
429             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
430         }
431         case DeclType::NAMESPACE: {
432             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
433         }
434         case DeclType::IMPORT_EQUALS: {
435             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
436         }
437         case DeclType::INTERFACE: {
438             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
439         }
440         default: {
441             if (currentVariable) {
442                 return false;
443             }
444             return newDecl->IsImportOrExportDecl() ?
445                    AddLexical<ModuleVariable>(allocator, currentVariable, newDecl) :
446                    AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
447         }
448     }
449 }
450 
451 // LocalScope
452 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)453 bool LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
454                             [[maybe_unused]] ScriptExtension extension)
455 {
456     return AddLocal(allocator, currentVariable, newDecl, extension);
457 }
458 
InitVariable()459 void LoopScope::InitVariable()
460 {
461     for (const auto &[name, var] : bindings_) {
462         if (!var->Declaration()->IsLetOrConstOrClassDecl()) {
463             continue;
464         }
465 
466         var->AddFlag(VariableFlags::INITIALIZED);
467         if (var->LexicalBound()) {
468             var->AddFlag(VariableFlags::PER_ITERATION);
469         }
470     }
471 }
472 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)473 bool CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
474                                  [[maybe_unused]] ScriptExtension extension)
475 {
476     return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED);
477 }
478 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)479 bool CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
480                             [[maybe_unused]] ScriptExtension extension)
481 {
482     if (!newDecl->IsVarDecl() && paramScope_->FindLocal(newDecl->Name())) {
483         return false;
484     }
485 
486     return AddLocal(allocator, currentVariable, newDecl, extension);
487 }
488 
489 }  // namespace panda::es2panda::binder
490