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/base/classDefinition.h>
26 #include <ir/expressions/identifier.h>
27 #include <ir/expressions/literals/stringLiteral.h>
28 #include <ir/expressions/privateIdentifier.h>
29 #include <ir/module/exportAllDeclaration.h>
30 #include <ir/module/exportNamedDeclaration.h>
31 #include <ir/module/exportSpecifier.h>
32 #include <ir/module/importDeclaration.h>
33 #include <ir/ts/tsModuleDeclaration.h>
34 #include <ir/ts/tsEnumDeclaration.h>
35 #include <macros.h>
36 #include <util/concurrent.h>
37 #include <util/ustring.h>
38
39 #include <algorithm>
40 #include <sstream>
41
42 namespace panda::es2panda::binder {
43
EnclosingVariableScope()44 VariableScope *Scope::EnclosingVariableScope()
45 {
46 Scope *iter = this;
47
48 while (iter) {
49 if (iter->IsVariableScope()) {
50 return iter->AsVariableScope();
51 }
52
53 iter = iter->Parent();
54 }
55
56 return nullptr;
57 }
58
EnclosingFunctionVariableScope()59 FunctionScope *Scope::EnclosingFunctionVariableScope()
60 {
61 Scope *iter = this;
62 while (iter) {
63 if (iter->IsFunctionVariableScope()) {
64 return iter->AsFunctionVariableScope();
65 }
66
67 iter = iter->Parent();
68 }
69
70 return nullptr;
71 }
72
FindLocal(const util::StringView &name, ResolveBindingOptions options) const73 Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
74 {
75 if (options & ResolveBindingOptions::INTERFACES) {
76 const std::string &interfaceName = binder::TSBinding::ToTSBinding(name);
77
78 auto res = bindings_.find(util::StringView{interfaceName});
79 if (res != bindings_.end()) {
80 return res->second;
81 }
82
83 if (!(options & ResolveBindingOptions::BINDINGS)) {
84 return nullptr;
85 }
86 }
87
88 auto res = bindings_.find(name);
89 if (res == bindings_.end()) {
90 return nullptr;
91 }
92
93 return res->second;
94 }
95
CalculateLevelInCorrespondingFunctionScope(const FunctionParamScope *scope, uint32_t &lexLevel, uint32_t &sendableLevel) const96 void Scope::CalculateLevelInCorrespondingFunctionScope(const FunctionParamScope *scope, uint32_t &lexLevel,
97 uint32_t &sendableLevel) const
98 {
99 auto *funcVariableScope = scope->GetFunctionScope();
100 // we may only have function param scope without function scope in TS here
101 if (funcVariableScope == nullptr) {
102 return;
103 }
104
105 if (funcVariableScope->NeedLexEnv()) {
106 lexLevel++;
107 }
108
109 if (funcVariableScope->NeedSendableEnv()) {
110 sendableLevel++;
111 }
112 }
113
Find(const util::StringView &name, ResolveBindingOptions options) const114 ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions options) const
115 {
116 uint32_t level = 0;
117 uint32_t lexLevel = 0;
118 uint32_t sendableLevel = 0;
119 const auto *iter = this;
120 ir::ScriptFunction *concurrentFunc = nullptr;
121 // If the first scope is functionParamScope, it means its corresponding functionScope is not
122 // iterated. so by default we set prevScopeNotFunctionScope as true so under such case,
123 // functionScopeNotIterated will be true.
124 bool prevScopeNotFunctionScope = true;
125 bool lexical = false;
126
127 while (iter != nullptr) {
128 bool functionScopeNotIterated = iter->IsFunctionParamScope() && prevScopeNotFunctionScope;
129 Variable *v = iter->FindLocal(name, options);
130
131 if (v != nullptr) {
132 return {name, const_cast<Scope *>(iter), level, lexLevel, sendableLevel, v, concurrentFunc};
133 }
134
135 if (iter->IsFunctionVariableScope() && !lexical) {
136 lexical = true;
137 }
138
139 if (iter->IsFunctionScope() && !concurrentFunc) {
140 if (iter->Node()->AsScriptFunction()->IsConcurrent()) {
141 concurrentFunc = const_cast<ir::ScriptFunction *>(iter->Node()->AsScriptFunction());
142 }
143 }
144
145 if (iter->IsVariableScope()) {
146 if (lexical) {
147 level++;
148 }
149
150 if (iter->AsVariableScope()->NeedLexEnv()) {
151 lexLevel++;
152 }
153
154 if (iter->AsVariableScope()->NeedSendableEnv()) {
155 sendableLevel++;
156 }
157 } else if (functionScopeNotIterated) {
158 level++;
159 CalculateLevelInCorrespondingFunctionScope(iter->AsFunctionParamScope(), lexLevel, sendableLevel);
160 }
161
162 prevScopeNotFunctionScope = !iter->IsFunctionVariableScope();
163 iter = iter->Parent();
164 }
165
166 return {name, nullptr, 0, 0, 0, nullptr, concurrentFunc};
167 }
168
Find(const ir::Expression *expr, bool onlyLevel) const169 std::pair<uint32_t, uint32_t> Scope::Find(const ir::Expression *expr, bool onlyLevel) const
170 {
171 uint32_t lexLevel = 0;
172 const auto *iter = this;
173
174 while (iter != nullptr) {
175 if (iter->Type() == ScopeType::CLASS) {
176 if (onlyLevel) {
177 return {lexLevel, 0};
178 }
179 return {lexLevel, iter->AsClassScope()->GetSlot(expr)};
180 }
181
182 if (iter->IsVariableScope()) {
183 if (iter->AsVariableScope()->NeedLexEnv()) {
184 lexLevel++;
185 }
186 }
187 iter = iter->Parent();
188 }
189
190 UNREACHABLE();
191 }
192
IsVariableScope() const193 bool ClassScope::IsVariableScope() const
194 {
195 // sendable class does not need a lexical env, handle it's scope as a non-variable scope
196 return !node_->AsClassDefinition()->IsSendable();
197 }
198
GetPrivateProperty(const util::StringView &name, bool isSetter) const199 Result ClassScope::GetPrivateProperty(const util::StringView &name, bool isSetter) const
200 {
201 if (name.Is("#method")) {
202 return {instanceMethodValidation_, false, false, false, false, 0};
203 }
204
205 uint32_t slot{0};
206 bool setter{false};
207 bool getter{false};
208
209 if (privateNames_.find(name) != privateNames_.end()) {
210 slot = privateNames_.find(name)->second;
211 } else {
212 auto accessor = isSetter ? privateSetters_ : privateGetters_;
213 auto unexpectedAccessor = isSetter ? privateGetters_ : privateSetters_;
214
215 if (accessor.find(name) != accessor.end()) {
216 setter = isSetter;
217 getter = !setter;
218 slot = accessor.find(name)->second;
219 } else {
220 getter = isSetter;
221 setter = !getter;
222 slot = unexpectedAccessor.find(name)->second;
223 }
224 }
225
226 uint32_t validateMethodSlot{0};
227
228 if (IsMethod(slot)) {
229 validateMethodSlot = IsStaticMethod(slot) ? staticMethodValidation_ : instanceMethodValidation_;
230 }
231
232 return {slot, IsMethod(slot), IsStaticMethod(slot), getter, setter, validateMethodSlot};
233 }
234
AddPrivateName(std::vector<const ir::Statement *> privateProperties, uint32_t privateFieldCnt, uint32_t instancePrivateMethodCnt, uint32_t staticPrivateMethodCnt)235 void ClassScope::AddPrivateName(std::vector<const ir::Statement *> privateProperties, uint32_t privateFieldCnt,
236 uint32_t instancePrivateMethodCnt, uint32_t staticPrivateMethodCnt)
237 {
238 privateFieldCnt_ = privateFieldCnt;
239 instancePrivateMethodStartSlot_ = slotIndex_ + privateFieldCnt_;
240 staticPrivateMethodStartSlot_ = instancePrivateMethodStartSlot_ + instancePrivateMethodCnt;
241 uint32_t instancePrivateMethodSlot = instancePrivateMethodStartSlot_;
242 uint32_t staticPrivateMethodSlot = staticPrivateMethodStartSlot_;
243 for (const auto *stmt : privateProperties) {
244 if (stmt->IsClassProperty()) {
245 privateNames_[stmt->AsClassProperty()->Key()->AsPrivateIdentifier()->Name()] = slotIndex_++;
246 continue;
247 }
248 ASSERT(stmt->IsMethodDefinition());
249 auto *methodDef = stmt->AsMethodDefinition();
250 uint32_t *start = methodDef->IsStatic() ? &staticPrivateMethodSlot : &instancePrivateMethodSlot;
251 auto name = methodDef->Key()->AsPrivateIdentifier()->Name();
252 switch (methodDef->Kind()) {
253 case ir::MethodDefinitionKind::GET: {
254 privateGetters_[name] = (*start)++;
255 continue;
256 }
257 case ir::MethodDefinitionKind::SET: {
258 privateSetters_[name] = (*start)++;
259 continue;
260 }
261 default: {
262 privateNames_[name]= (*start)++;
263 continue;
264 }
265 }
266 }
267 slotIndex_ = staticPrivateMethodSlot;
268 privateMethodEndSlot_ = slotIndex_;
269 if (instancePrivateMethodCnt != 0) {
270 instanceMethodValidation_ = slotIndex_++;
271 }
272
273 if (staticPrivateMethodCnt != 0) {
274 staticMethodValidation_ = slotIndex_++;
275 }
276 }
277
GetSelfScopeName()278 util::StringView ClassScope::GetSelfScopeName()
279 {
280 if (hasSelfScopeNameSet_) {
281 return selfScopeName_;
282 }
283
284 std::stringstream scopeName;
285
286 if (node_ && node_->IsClassDefinition() && node_->AsClassDefinition()->Ident()) {
287 util::StringView selfName = node_->AsClassDefinition()->Ident()->Name();
288 scopeName << selfName;
289 return util::UString(scopeName.str(), allocator_).View();
290 }
291 // To get the name for anonymous class
292 if (node_ && node_->Parent() && node_->Parent()->Parent()) {
293 scopeName << util::Helpers::GetName(allocator_, node_->Parent()->Parent());
294 return util::UString(scopeName.str(), allocator_).View();
295 }
296
297 return util::UString(scopeName.str(), allocator_).View();
298 }
299
GetScopeTag()300 util::StringView ClassScope::GetScopeTag()
301 {
302 return util::UString(util::Helpers::CLASS_SCOPE_TAG.data(), allocator_).View();
303 }
304
FindPrivateName(const util::StringView &name, bool isSetter) const305 PrivateNameFindResult Scope::FindPrivateName(const util::StringView &name, bool isSetter) const
306 {
307 uint32_t lexLevel = 0;
308 const auto *iter = this;
309
310 while (iter != nullptr) {
311 if (iter->Type() == ScopeType::CLASS) {
312 const auto *classScope = iter->AsClassScope();
313 if (name.Is("#method") || classScope->HasPrivateName(name)) {
314 return {lexLevel, classScope->GetPrivateProperty(name, isSetter)};
315 }
316 }
317
318 if (iter->IsVariableScope()) {
319 if (iter->AsVariableScope()->NeedLexEnv()) {
320 lexLevel++;
321 }
322 }
323 iter = iter->Parent();
324 }
325
326 UNREACHABLE();
327 }
328
FindDecl(const util::StringView &name) const329 Decl *Scope::FindDecl(const util::StringView &name) const
330 {
331 for (auto *it : decls_) {
332 if (it->Name() == name) {
333 return it;
334 }
335 }
336
337 return nullptr;
338 }
339
HasVarDecl(const util::StringView &name) const340 bool Scope::HasVarDecl(const util::StringView &name) const
341 {
342 for (auto *it : decls_) {
343 if (it->Name() == name && it->IsVarDecl()) {
344 return true;
345 }
346 }
347
348 return false;
349 }
350
IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor)351 std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor)
352 {
353 auto *iter = this;
354
355 while (true) {
356 auto *v = iter->FindLocal(name);
357
358 if (v && visitor(v)) {
359 return {iter, true};
360 }
361
362 if (iter->IsFunctionVariableScope()) {
363 break;
364 }
365
366 iter = iter->Parent();
367 }
368
369 return {iter, false};
370 }
371
SetFullScopeNames()372 void Scope::SetFullScopeNames()
373 {
374 if (hasFullScopeNameSet_) {
375 return;
376 }
377 hasFullScopeNameSet_ = true;
378 if (!hasSelfScopeNameSet_) {
379 SetSelfScopeName(GetSelfScopeName());
380 }
381
382 std::stringstream selfScopeStream;
383 OptimizeSelfScopeName(selfScopeStream);
384 std::stringstream fullScopeName;
385 Scope *parent = GetParentWithScopeName();
386 if (parent) {
387 fullScopeName << parent->GetFullScopeName() <<
388 GetScopeTag() <<
389 selfScopeStream.str();
390 if (scopeDuplicateIndex_ > 0) {
391 fullScopeName << util::Helpers::DUPLICATED_SEPERATOR <<
392 std::hex << scopeDuplicateIndex_;
393 }
394 }
395
396 fullScopeName_ = util::UString(fullScopeName.str(), allocator_).View();
397 }
398
OptimizeSelfScopeName(std::stringstream &selfScopeStream)399 void Scope::OptimizeSelfScopeName(std::stringstream &selfScopeStream)
400 {
401 bool useIndex = false;
402 auto it = topScope_->scopeNames_.find(selfScopeName_);
403 if (it == topScope_->scopeNames_.end()) {
404 std::stringstream indexScopeName;
405 indexScopeName << util::Helpers::INDEX_NAME_SPICIFIER << std::hex << topScope_->scopeNames_.size();
406 if (selfScopeName_.Length() > indexScopeName.str().length()) {
407 topScope_->scopeNames_.insert(
408 {selfScopeName_, (int32_t)topScope_->scopeNames_.size()}
409 );
410 selfScopeStream << indexScopeName.str();
411 useIndex = true;
412 }
413 } else {
414 selfScopeStream << util::Helpers::INDEX_NAME_SPICIFIER << std::hex << it->second;
415 useIndex = true;
416 }
417
418 if (!useIndex) {
419 selfScopeStream << selfScopeName_;
420 }
421 }
422
AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)423 bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
424 [[maybe_unused]] ScriptExtension extension)
425 {
426 VariableFlags flags = VariableFlags::NONE;
427 switch (newDecl->Type()) {
428 case DeclType::VAR: {
429 auto [scope, shadowed] = IterateShadowedVariables(
430 newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
431
432 if (shadowed) {
433 return false;
434 }
435
436 VariableFlags varFlags = VariableFlags::HOIST_VAR;
437 if (scope->IsGlobalScope()) {
438 scope->Bindings().insert({newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)});
439 } else {
440 scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags);
441 }
442
443 return true;
444 }
445 case DeclType::ENUM_LITERAL: {
446 return tsBindings_.AddTSVariable<TSBindingType::ENUMLITERAL>(
447 newDecl->Name(), allocator->New<EnumLiteralVariable>(newDecl, VariableFlags::ENUM_LITERAL));
448 }
449 case DeclType::INTERFACE: {
450 bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)});
451 return true;
452 }
453 case DeclType::FUNC: {
454 flags = VariableFlags::HOIST;
455 [[fallthrough]];
456 }
457 default: {
458 if (currentVariable) {
459 return false;
460 }
461
462 if (HasVarDecl(newDecl->Name())) {
463 return false;
464 }
465
466 bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)});
467 return true;
468 }
469 }
470 }
471
AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)472 bool ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)
473 {
474 CHECK_NOT_NULL(newDecl);
475 ASSERT(newDecl->IsParameterDecl());
476
477 if (currentVariable) {
478 return false;
479 }
480
481 auto *param = allocator->New<LocalVariable>(newDecl, flags);
482
483 params_.push_back(param);
484 bindings_.insert({newDecl->Name(), param});
485 return true;
486 }
487
AddParamDecl(ArenaAllocator *allocator, const ir::AstNode *param)488 std::tuple<ParameterDecl *, const ir::AstNode *> ParamScope::AddParamDecl(ArenaAllocator *allocator,
489 const ir::AstNode *param)
490 {
491 const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size());
492
493 auto *decl = NewDecl<ParameterDecl>(allocator, name);
494 CHECK_NOT_NULL(decl);
495
496 if (!AddParam(allocator, FindLocal(name), decl, VariableFlags::VAR)) {
497 return {decl, param};
498 }
499
500 if (!pattern) {
501 decl->BindNode(param);
502 return {decl, nullptr};
503 }
504
505 std::vector<const ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param);
506
507 for (const auto *binding : bindings) {
508 auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name());
509 CHECK_NOT_NULL(varDecl);
510 varDecl->BindNode(binding);
511
512 if (FindLocal(varDecl->Name())) {
513 return {decl, binding};
514 }
515
516 auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR);
517 bindings_.insert({varDecl->Name(), paramVar});
518 }
519
520 return {decl, nullptr};
521 }
522
BindName(ArenaAllocator *allocator, util::StringView name)523 void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name)
524 {
525 nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED);
526 functionScope_->Bindings().insert({name, nameVar_});
527 }
528
AddBinding([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl, [[maybe_unused]] ScriptExtension extension)529 bool FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
530 [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
531 [[maybe_unused]] ScriptExtension extension)
532 {
533 UNREACHABLE();
534 }
535
GetFullScopeName()536 const util::StringView &FunctionParamScope::GetFullScopeName()
537 {
538 if (functionScope_) {
539 return functionScope_->GetFullScopeName();
540 }
541
542 // FunctionParam should have the same name with FunctionScope
543 // Get scope name from parent in case the functionScope_ is nullptr
544 if (parent_) {
545 return parent_->GetFullScopeName();
546 }
547
548 return fullScopeName_;
549 }
550
GetDuplicateScopeIndex(const util::StringView &childScopeName)551 uint32_t FunctionParamScope::GetDuplicateScopeIndex(const util::StringView &childScopeName)
552 {
553 if (functionScope_) {
554 return functionScope_->GetDuplicateScopeIndex(childScopeName);
555 }
556
557 if (parent_) {
558 return parent_->GetDuplicateScopeIndex(childScopeName);
559 }
560
561 return 0;
562 }
563
BindNameWithScopeInfo(util::StringView name, util::StringView recordName)564 void FunctionScope::BindNameWithScopeInfo(util::StringView name, util::StringView recordName)
565 {
566 name_ = name;
567 std::stringstream internalName;
568 internalName << recordName << util::Helpers::FUNC_NAME_SEPARATOR;
569
570 Scope *parent = GetParentWithScopeName();
571 if (parent != nullptr) {
572 internalName << parent->GetFullScopeName();
573 }
574 internalName << GetScopeTag() << util::Helpers::FUNC_NAME_SEPARATOR << GetSelfScopeName();
575 if (scopeDuplicateIndex_ > 0) {
576 internalName << util::Helpers::DUPLICATED_SEPERATOR <<
577 std::hex << scopeDuplicateIndex_;
578 }
579 internalName_ = util::UString(internalName.str(), allocator_).View();
580 }
581
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)582 bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
583 [[maybe_unused]] ScriptExtension extension)
584 {
585 switch (newDecl->Type()) {
586 case DeclType::VAR: {
587 return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
588 }
589 case DeclType::FUNC: {
590 return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
591 }
592 case DeclType::CLASS: {
593 return AddClass<LocalVariable>(allocator, currentVariable, newDecl);
594 }
595 case DeclType::ENUM_LITERAL: {
596 return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
597 }
598 case DeclType::NAMESPACE: {
599 return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
600 }
601 case DeclType::IMPORT_EQUALS: {
602 return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
603 }
604 case DeclType::INTERFACE: {
605 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
606 }
607 default: {
608 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
609 }
610 }
611 }
612
SetSelfScopeName(const util::StringView &ident)613 void FunctionScope::SetSelfScopeName(const util::StringView &ident)
614 {
615 Scope::SetSelfScopeName(ident);
616 paramScope_->selfScopeName_ = selfScopeName_;
617 paramScope_->hasSelfScopeNameSet_ = true;
618 hasSelfScopeNameSet_ = true;
619 }
620
GetScopeTag()621 util::StringView FunctionScope::GetScopeTag()
622 {
623 if (IsFunctionScope() && (node_->IsScriptFunction() && node_->AsScriptFunction()->IsConstructor())) {
624 return util::UString(util::Helpers::CTOR_TAG.data(), allocator_).View();
625 }
626 if (parent_ && parent_->Parent() && parent_->Parent()->IsClassScope()) {
627 bool hasNodeParent = node_ && node_->Parent() && node_->Parent()->Parent();
628 const ir::AstNode *nodeParent = hasNodeParent ? node_->Parent()->Parent() : nullptr;
629 if (nodeParent && nodeParent->IsMethodDefinition() && nodeParent->AsMethodDefinition()->IsStatic()) {
630 return util::UString(util::Helpers::STATIC_METHOD_TAG.data(), allocator_).View();
631 }
632 return util::UString(util::Helpers::METHOD_TAG.data(), allocator_).View();
633 }
634 return util::UString(util::Helpers::FUNCTION_TAG.data(), allocator_).View();
635 }
636
GetSelfScopeName()637 util::StringView FunctionScope::GetSelfScopeName()
638 {
639 if (hasSelfScopeNameSet_) {
640 return selfScopeName_;
641 }
642
643 if (node_ && node_->IsScriptFunction()) {
644 auto selfName = util::Helpers::FunctionName(allocator_, node_->AsScriptFunction());
645 if (!util::Helpers::IsSpecialScopeName(selfName)) {
646 return selfName;
647 }
648 }
649 return util::UString(util::Helpers::STRING_EMPTY.data(), allocator_).View();
650 }
651
GetSelfScopeName()652 util::StringView TSModuleScope::GetSelfScopeName()
653 {
654 if (hasSelfScopeNameSet_) {
655 return selfScopeName_;
656 }
657 throw Error(ErrorType::GENERIC, "namespace or module name should be set in Binder::ResolveReference()");
658 }
659
GetScopeTag()660 util::StringView TSModuleScope::GetScopeTag()
661 {
662 return util::UString(util::Helpers::NAMESPACE_TAG.data(), allocator_).View();
663 }
664
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)665 bool TSEnumScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
666 [[maybe_unused]] ScriptExtension extension)
667 {
668 ASSERT(newDecl->Type() == DeclType::ENUM);
669 return enumMemberBindings_->insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)}).second;
670 }
671
SetSelfScopeName(const util::StringView &ident)672 void TSEnumScope::SetSelfScopeName(const util::StringView &ident)
673 {
674 if (!hasSelfScopeNameSet_) {
675 FunctionScope::SetSelfScopeName(GetSelfScopeName());
676 }
677 }
678
GetSelfScopeName()679 util::StringView TSEnumScope::GetSelfScopeName()
680 {
681 if (hasSelfScopeNameSet_) {
682 return selfScopeName_;
683 }
684
685 std::stringstream scopeName;
686 if (node_ && node_->IsScriptFunction()) {
687 auto scriptFunction = node_->AsScriptFunction();
688 if (scriptFunction->Params().size() > 0 && scriptFunction->Params()[0]->IsIdentifier()) {
689 scopeName << scriptFunction->Params()[0]->AsIdentifier()->Name();
690 }
691 }
692 return util::UString(scopeName.str(), allocator_).View();
693 }
694
GetScopeTag()695 util::StringView TSEnumScope::GetScopeTag()
696 {
697 return util::UString(util::Helpers::ENUM_TAG.data(), allocator_).View();
698 }
699
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)700 bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
701 [[maybe_unused]] ScriptExtension extension)
702 {
703 switch (newDecl->Type()) {
704 case DeclType::VAR: {
705 return AddVar<GlobalVariable>(allocator, currentVariable, newDecl);
706 }
707 case DeclType::FUNC: {
708 return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension);
709 }
710 case DeclType::CLASS: {
711 return AddClass<LocalVariable>(allocator, currentVariable, newDecl);
712 }
713 case DeclType::ENUM_LITERAL: {
714 return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
715 }
716 case DeclType::NAMESPACE: {
717 return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
718 }
719 case DeclType::IMPORT_EQUALS: {
720 return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
721 }
722 case DeclType::INTERFACE: {
723 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
724 }
725 default: {
726 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
727 }
728 }
729
730 return true;
731 }
732
SetSelfScopeName([[maybe_unused]] const util::StringView &ident)733 void GlobalScope::SetSelfScopeName([[maybe_unused]] const util::StringView &ident)
734 {
735 hasSelfScopeNameSet_ = true;
736 }
737
738 // ModuleScope
739
ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName)740 void ModuleScope::ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName)
741 {
742 auto res = bindings_.find(localName);
743 // Since the module's exported [localName] has been validated before,
744 // [localName] must have a binding now.
745 ASSERT(res != bindings_.end());
746 if (!res->second->IsModuleVariable()) {
747 auto *decl = res->second->Declaration();
748 decl->AddFlag(DeclarationFlags::EXPORT);
749 VariableFlags flags = res->second->Flags();
750 res->second = allocator->New<ModuleVariable>(decl, flags | VariableFlags::LOCAL_EXPORT);
751 }
752 }
753
AssignIndexToModuleVariable(util::StringView name, uint32_t index)754 void ModuleScope::AssignIndexToModuleVariable(util::StringView name, uint32_t index)
755 {
756 auto *moduleVar = FindLocal(name);
757 CHECK_NOT_NULL(moduleVar);
758 ASSERT(moduleVar->IsModuleVariable());
759 moduleVar->AsModuleVariable()->AssignIndex(index);
760 }
761
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)762 bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
763 [[maybe_unused]] ScriptExtension extension)
764 {
765 switch (newDecl->Type()) {
766 case DeclType::VAR: {
767 auto [scope, shadowed] = IterateShadowedVariables(
768 newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
769
770 if (shadowed) {
771 return false;
772 }
773 return newDecl->IsImportOrExportDecl() ?
774 AddVar<ModuleVariable>(allocator, currentVariable, newDecl) :
775 AddVar<LocalVariable>(allocator, currentVariable, newDecl);
776 }
777 case DeclType::FUNC: {
778 if (currentVariable) {
779 auto decl = currentVariable->Declaration();
780 if (!decl->IsClassDecl() || !decl->AsClassDecl()->IsDeclare()) {
781 return false;
782 }
783 }
784 return newDecl->IsImportOrExportDecl() ?
785 AddFunction<ModuleVariable>(allocator, currentVariable, newDecl, extension) :
786 AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
787 }
788 case DeclType::CLASS: {
789 return newDecl->IsImportOrExportDecl() ?
790 AddClass<ModuleVariable>(allocator, currentVariable, newDecl) :
791 AddClass<LocalVariable>(allocator, currentVariable, newDecl);
792 }
793 case DeclType::ENUM_LITERAL: {
794 return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
795 }
796 case DeclType::NAMESPACE: {
797 return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
798 }
799 case DeclType::IMPORT_EQUALS: {
800 return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
801 }
802 case DeclType::INTERFACE: {
803 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
804 }
805 default: {
806 if (currentVariable) {
807 return false;
808 }
809 return newDecl->IsImportOrExportDecl() ?
810 AddLexical<ModuleVariable>(allocator, currentVariable, newDecl) :
811 AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
812 }
813 }
814 }
815
SetSelfScopeName([[maybe_unused]] const util::StringView &ident)816 void ModuleScope::SetSelfScopeName([[maybe_unused]] const util::StringView &ident)
817 {
818 hasSelfScopeNameSet_ = true;
819 }
820
821 // LocalScope
822
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)823 bool LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
824 [[maybe_unused]] ScriptExtension extension)
825 {
826 return AddLocal(allocator, currentVariable, newDecl, extension);
827 }
828
InitVariable()829 void LoopScope::InitVariable()
830 {
831 for (const auto &[name, var] : bindings_) {
832 if (!var->Declaration()->IsLetOrConstOrClassDecl()) {
833 continue;
834 }
835
836 var->AddFlag(VariableFlags::INITIALIZED);
837 if (var->LexicalBound()) {
838 var->AddFlag(VariableFlags::PER_ITERATION);
839 }
840 }
841 }
842
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)843 bool CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
844 [[maybe_unused]] ScriptExtension extension)
845 {
846 return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED);
847 }
848
AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)849 bool CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
850 [[maybe_unused]] ScriptExtension extension)
851 {
852 if (!newDecl->IsVarDecl() && paramScope_->FindLocal(newDecl->Name())) {
853 return false;
854 }
855
856 return AddLocal(allocator, currentVariable, newDecl, extension);
857 }
858 } // namespace panda::es2panda::binder
859