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