1 /**
2 * Copyright (c) 2021-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 "scope.h"
17
18 #include "varbinder/declaration.h"
19 #include "util/helpers.h"
20 #include "varbinder/tsBinding.h"
21 #include "varbinder/variable.h"
22 #include "varbinder/variableFlags.h"
23 #include "ir/astNode.h"
24 #include "ir/expressions/identifier.h"
25 #include "ir/statements/annotationDeclaration.h"
26 #include "ir/statements/classDeclaration.h"
27 #include "ir/base/classDefinition.h"
28 #include "ir/base/scriptFunction.h"
29 #include "ir/base/classProperty.h"
30 #include "ir/base/methodDefinition.h"
31 #include "ir/module/exportAllDeclaration.h"
32 #include "ir/module/exportNamedDeclaration.h"
33 #include "ir/module/exportSpecifier.h"
34 #include "ir/module/importDeclaration.h"
35 #include "ir/expressions/literals/stringLiteral.h"
36 #include "ir/expressions/literals/booleanLiteral.h"
37 #include "ir/ts/tsInterfaceDeclaration.h"
38 #include "ir/ts/tsEnumDeclaration.h"
39 #include "ir/ts/tsTypeAliasDeclaration.h"
40 #include "compiler/base/literals.h"
41 #include "macros.h"
42 #include "util/ustring.h"
43 #include "generated/signatures.h"
44 #include "public/public.h"
45
46 namespace ark::es2panda::varbinder {
EnclosingVariableScope()47 VariableScope *Scope::EnclosingVariableScope()
48 {
49 Scope *iter = this;
50
51 while (iter != nullptr) {
52 if (iter->IsVariableScope()) {
53 return iter->AsVariableScope();
54 }
55
56 iter = iter->Parent();
57 }
58
59 return nullptr;
60 }
61
EnclosingVariableScope() const62 const VariableScope *Scope::EnclosingVariableScope() const
63 {
64 const auto *iter = this;
65
66 while (iter != nullptr) {
67 if (iter->IsVariableScope()) {
68 return iter->AsVariableScope();
69 }
70
71 iter = iter->Parent();
72 }
73
74 return nullptr;
75 }
76
IsSuperscopeOf(const varbinder::Scope * subscope) const77 bool Scope::IsSuperscopeOf(const varbinder::Scope *subscope) const
78 {
79 while (subscope != nullptr) {
80 if (subscope == this) {
81 return true;
82 }
83 subscope = ir::AstNode::EnclosingScope(subscope->Node()->Parent());
84 }
85 return false;
86 }
87
88 // NOTE(psiket): Duplication
EnclosingClassScope()89 ClassScope *Scope::EnclosingClassScope()
90 {
91 Scope *iter = this;
92
93 while (iter != nullptr) {
94 if (iter->IsClassScope()) {
95 return iter->AsClassScope();
96 }
97
98 iter = iter->Parent();
99 }
100
101 return nullptr;
102 }
103
EnclosingClassScope() const104 const ClassScope *Scope::EnclosingClassScope() const
105 {
106 const auto *iter = this;
107
108 while (iter != nullptr) {
109 if (iter->IsVariableScope()) {
110 return iter->AsClassScope();
111 }
112
113 iter = iter->Parent();
114 }
115
116 return nullptr;
117 }
118
FindLocal(const util::StringView & name,ResolveBindingOptions options) const119 Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
120 {
121 if ((options & ResolveBindingOptions::INTERFACES) != 0) {
122 std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name);
123 util::StringView interfaceNameView(tsBindingName);
124
125 auto res = bindings_.find(interfaceNameView);
126 if (res != bindings_.end()) {
127 return res->second;
128 }
129
130 if ((options & ResolveBindingOptions::BINDINGS) == 0) {
131 return nullptr;
132 }
133 }
134
135 auto res = bindings_.find(name);
136 if (res == bindings_.end()) {
137 return nullptr;
138 }
139
140 return res->second;
141 }
142
InsertBinding(const util::StringView & name,Variable * const var)143 Scope::InsertResult Scope::InsertBinding(const util::StringView &name, Variable *const var)
144 {
145 ASSERT(var != nullptr);
146 auto insertResult = bindings_.emplace(name, var);
147 if (insertResult.second) {
148 decls_.push_back(var->Declaration());
149 }
150
151 return insertResult;
152 }
153
TryInsertBinding(const util::StringView & name,Variable * const var)154 Scope::InsertResult Scope::TryInsertBinding(const util::StringView &name, Variable *const var)
155 {
156 ASSERT(var != nullptr);
157 return bindings_.try_emplace(name, var);
158 }
159
MergeBindings(VariableMap const & bindings)160 void Scope::MergeBindings(VariableMap const &bindings)
161 {
162 for (auto &[k, v] : bindings) {
163 bindings_.try_emplace(k, v);
164 }
165 }
166
EraseBinding(const util::StringView & name)167 Scope::VariableMap::size_type Scope::EraseBinding(const util::StringView &name)
168 {
169 if (auto toBeErased = bindings_.find(name);
170 toBeErased == bindings_.end() ||
171 (toBeErased->second->IsLocalVariable() &&
172 toBeErased->second->AsLocalVariable()->Declaration()->Node()->IsImportNamespaceSpecifier())) {
173 return 0;
174 }
175
176 return bindings_.erase(name);
177 }
178
FindInGlobal(const util::StringView & name,const ResolveBindingOptions options) const179 ConstScopeFindResult Scope::FindInGlobal(const util::StringView &name, const ResolveBindingOptions options) const
180 {
181 const auto *scopeIter = this;
182 const auto *scopeParent = this->Parent();
183 // One scope below true global is ETSGLOBAL
184 while (scopeParent != nullptr && !scopeParent->IsGlobalScope()) {
185 scopeIter = scopeParent;
186 scopeParent = scopeIter->Parent();
187 }
188
189 auto *resolved = scopeIter->FindLocal(name, options);
190 if (resolved == nullptr && scopeParent != nullptr) {
191 // If the variable cannot be found in the scope of the local ETSGLOBAL, than we still need to check the true
192 // global scope which contains all the imported ETSGLOBALs
193 resolved = scopeParent->FindLocal(name, options);
194 }
195
196 return {name, scopeIter, 0, 0, resolved};
197 }
198
FindInFunctionScope(const util::StringView & name,const ResolveBindingOptions options) const199 ConstScopeFindResult Scope::FindInFunctionScope(const util::StringView &name, const ResolveBindingOptions options) const
200 {
201 const auto *scopeIter = this;
202 while (scopeIter != nullptr && !scopeIter->IsGlobalScope()) {
203 if (!scopeIter->IsClassScope()) {
204 if (auto *const resolved = scopeIter->FindLocal(name, options); resolved != nullptr) {
205 return ConstScopeFindResult(name, scopeIter, 0, 0, resolved);
206 }
207 }
208 scopeIter = scopeIter->Parent();
209 }
210
211 return ConstScopeFindResult(name, scopeIter, 0, 0, nullptr);
212 }
213
Find(const util::StringView & name,const ResolveBindingOptions options)214 ScopeFindResult Scope::Find(const util::StringView &name, const ResolveBindingOptions options)
215 {
216 return FindImpl<ScopeFindResult>(this, name, options);
217 }
218
Find(const util::StringView & name,const ResolveBindingOptions options) const219 ConstScopeFindResult Scope::Find(const util::StringView &name, const ResolveBindingOptions options) const
220 {
221 return FindImpl<ConstScopeFindResult>(this, name, options);
222 }
223
FindDecl(const util::StringView & name) const224 Decl *Scope::FindDecl(const util::StringView &name) const
225 {
226 for (auto *it : decls_) {
227 if (it->Name() == name) {
228 return it;
229 }
230 }
231
232 return nullptr;
233 }
234
IterateShadowedVariables(const util::StringView & name,const VariableVisitor & visitor)235 std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitor &visitor)
236 {
237 auto *iter = this;
238
239 while (iter != nullptr) {
240 auto *v = iter->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS);
241
242 if (v != nullptr && visitor(v)) {
243 return {iter, true};
244 }
245
246 if (iter->IsFunctionVariableScope()) {
247 break;
248 }
249
250 iter = iter->Parent();
251 }
252
253 return {iter, false};
254 }
255
AddLocalVar(ArenaAllocator * allocator,Decl * newDecl)256 Variable *Scope::AddLocalVar(ArenaAllocator *allocator, Decl *newDecl)
257 {
258 auto [scope, shadowed] =
259 IterateShadowedVariables(newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
260
261 if (shadowed) {
262 return nullptr;
263 }
264
265 VariableFlags varFlags = VariableFlags::HOIST_VAR | VariableFlags::LEXICAL_VAR;
266 if (scope->IsGlobalScope()) {
267 return scope->InsertBinding(newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)).first->second;
268 }
269
270 return scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags);
271 }
272
AddLocal(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)273 Variable *Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
274 [[maybe_unused]] ScriptExtension extension)
275 {
276 VariableFlags flags = VariableFlags::LEXICAL;
277 switch (newDecl->Type()) {
278 case DeclType::VAR: {
279 return AddLocalVar(allocator, newDecl);
280 }
281 case DeclType::ENUM: {
282 return bindings_.insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)}).first->second;
283 }
284 case DeclType::ENUM_LITERAL: {
285 auto *var =
286 bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::ENUM_LITERAL)})
287 .first->second;
288 newDecl->Node()->AsTSEnumDeclaration()->Key()->SetVariable(var);
289 return var;
290 }
291 case DeclType::INTERFACE: {
292 return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)})
293 .first->second;
294 }
295 case DeclType::CLASS: {
296 auto *var =
297 bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::CLASS)})
298 .first->second;
299 newDecl->Node()->AsClassDefinition()->Ident()->SetVariable(var);
300 return var;
301 }
302 case DeclType::TYPE_PARAMETER: {
303 return bindings_
304 .insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::TYPE_PARAMETER)})
305 .first->second;
306 }
307 case DeclType::FUNC: {
308 flags = VariableFlags::HOIST;
309 [[fallthrough]];
310 }
311 default: {
312 if (currentVariable != nullptr) {
313 return nullptr;
314 }
315
316 auto [_, shadowed] = IterateShadowedVariables(
317 newDecl->Name(), [](const Variable *v) { return v->HasFlag(VariableFlags::LEXICAL_VAR); });
318 (void)_;
319
320 if (shadowed) {
321 return nullptr;
322 }
323
324 return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)}).first->second;
325 }
326 }
327 }
328
CheckDirectEval(public_lib::Context * context)329 void VariableScope::CheckDirectEval(public_lib::Context *context)
330 {
331 ASSERT(context);
332 const auto &varMap = Bindings();
333
334 if (!HasFlag(ScopeFlags::NO_REG_STORE) || varMap.empty()) {
335 evalBindings_ = compiler::INVALID_LITERAL_BUFFER_ID;
336 return;
337 }
338
339 size_t constBindings = 0;
340 for (const auto &[name, var] : varMap) {
341 (void)name;
342 var->SetLexical(this);
343
344 if (var->LexicalBound() && var->Declaration()->IsConstDecl()) {
345 constBindings++;
346 }
347 }
348
349 std::vector<compiler::Literal> literals(LexicalSlots() + constBindings, compiler::Literal(util::StringView()));
350
351 if (constBindings == 0U) {
352 for (const auto &[name, variable] : varMap) {
353 if (!variable->LexicalBound()) {
354 continue;
355 }
356
357 literals[variable->AsLocalVariable()->LexIdx()] = compiler::Literal(name);
358 }
359 } else {
360 std::vector<varbinder::Variable *> bindings(LexicalSlots());
361
362 for (const auto &[name, variable] : varMap) {
363 (void)name;
364 if (!variable->LexicalBound()) {
365 continue;
366 }
367
368 bindings[variable->AsLocalVariable()->LexIdx()] = variable;
369 }
370
371 uint32_t buffIndex = 0;
372 for (const auto *variable : bindings) {
373 if (variable == nullptr) {
374 ASSERT(literals[buffIndex].GetString().empty());
375 buffIndex++;
376 continue;
377 }
378 if (variable->Declaration()->IsConstDecl()) {
379 literals[buffIndex++] = compiler::Literal(true);
380 }
381 literals[buffIndex++] = compiler::Literal(variable->Name());
382 }
383 }
384 context->contextLiterals.emplace_back(literals);
385 evalBindings_ = context->contextLiterals.size() - 1;
386 }
387
AddParam(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,VariableFlags flags)388 Variable *ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)
389 {
390 ASSERT(newDecl->IsParameterDecl());
391
392 if (currentVariable != nullptr) {
393 return nullptr;
394 }
395
396 auto *param = allocator->New<LocalVariable>(newDecl, flags);
397 param->SetScope(this);
398
399 params_.push_back(param);
400 InsertBinding(newDecl->Name(), param);
401 return param;
402 }
403
AddParamDecl(ArenaAllocator * allocator,ir::AstNode * param)404 std::tuple<ParameterDecl *, ir::AstNode *, Variable *> ParamScope::AddParamDecl(ArenaAllocator *allocator,
405 ir::AstNode *param)
406 {
407 const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size());
408
409 auto *decl = NewDecl<ParameterDecl>(allocator, name);
410 auto *var = AddParam(allocator, FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS), decl,
411 VariableFlags::VAR | VariableFlags::LOCAL);
412
413 if (var == nullptr) {
414 return {decl, param, nullptr};
415 }
416
417 if (!pattern) {
418 decl->BindNode(param);
419 return {decl, nullptr, var};
420 }
421
422 std::vector<ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param);
423
424 for (auto *binding : bindings) {
425 auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name());
426 varDecl->BindNode(binding);
427
428 if (FindLocal(varDecl->Name(), varbinder::ResolveBindingOptions::BINDINGS) != nullptr) {
429 return {decl, binding, nullptr};
430 }
431
432 auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR | VariableFlags::LOCAL);
433 TryInsertBinding(varDecl->Name(), paramVar);
434 }
435
436 return {decl, nullptr, var};
437 }
438
BindName(ArenaAllocator * allocator,util::StringView name)439 void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name)
440 {
441 nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED);
442 if (!functionScope_->InsertBinding(name, nameVar_).second) {
443 nameVar_ = nullptr;
444 }
445 }
446
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)447 Variable *FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
448 [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
449 [[maybe_unused]] ScriptExtension extension)
450 {
451 UNREACHABLE();
452 }
453
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)454 Variable *AnnotationParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
455 [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
456 [[maybe_unused]] ScriptExtension extension)
457 {
458 auto *ident = newDecl->Node()->AsClassProperty()->Id();
459 auto annoVar = allocator->New<LocalVariable>(newDecl, VariableFlags::PROPERTY);
460 auto var = InsertBinding(ident->Name(), annoVar).first->second;
461 if (var != nullptr) {
462 var->SetScope(this);
463 if (ident != nullptr) {
464 ident->SetVariable(var);
465 }
466 }
467 return var;
468 }
469
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)470 Variable *FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
471 [[maybe_unused]] ScriptExtension extension)
472 {
473 ir::Identifier *ident {};
474 Variable *var {};
475 switch (newDecl->Type()) {
476 case DeclType::VAR: {
477 return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
478 }
479 case DeclType::FUNC: {
480 return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
481 }
482 case DeclType::ENUM: {
483 return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
484 }
485 case DeclType::ENUM_LITERAL: {
486 var = AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
487 ident = newDecl->Node()->AsTSEnumDeclaration()->Key();
488 break;
489 }
490 // NOTE(psiket):Duplication
491 case DeclType::INTERFACE: {
492 ident = newDecl->Node()->AsTSInterfaceDeclaration()->Id();
493 auto interfaceVar = allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE);
494 var = InsertBinding(newDecl->Name(), interfaceVar).first->second;
495 break;
496 }
497 case DeclType::CLASS: {
498 ident = newDecl->Node()->AsClassDefinition()->Ident();
499 auto classVar = allocator->New<LocalVariable>(newDecl, VariableFlags::CLASS);
500 var = InsertBinding(newDecl->Name(), classVar).first->second;
501 break;
502 }
503 case DeclType::TYPE_ALIAS: {
504 ident = newDecl->Node()->AsTSTypeAliasDeclaration()->Id();
505 var = typeAliasScope_->AddBinding(allocator, currentVariable, newDecl, extension);
506 break;
507 }
508 default: {
509 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
510 }
511 }
512 if (var != nullptr) {
513 var->SetScope(this);
514 if (ident != nullptr) {
515 ident->SetVariable(var);
516 }
517 }
518 return var;
519 }
520
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)521 Variable *GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
522 [[maybe_unused]] ScriptExtension extension)
523 {
524 switch (newDecl->Type()) {
525 case DeclType::VAR: {
526 return AddVar<GlobalVariable>(allocator, currentVariable, newDecl);
527 }
528 case DeclType::FUNC: {
529 return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension);
530 }
531 case DeclType::ENUM: {
532 return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
533 }
534 case DeclType::ENUM_LITERAL: {
535 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
536 }
537 case DeclType::INTERFACE: {
538 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
539 }
540 default: {
541 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
542 }
543 }
544 }
545
InsertBinding(const util::StringView & name,Variable * const var)546 Scope::InsertResult GlobalScope::InsertBinding(const util::StringView &name, Variable *const var)
547 {
548 return GlobalScope::InsertImpl(name, var, false, false);
549 }
550
TryInsertBinding(const util::StringView & name,Variable * const var)551 Scope::InsertResult GlobalScope::TryInsertBinding(const util::StringView &name, Variable *const var)
552 {
553 const auto insRes = Scope::TryInsertBinding(name, var);
554 if (insRes.second) {
555 [[maybe_unused]] const bool insertSuccess = std::get<1>(foreignBindings_.try_emplace(name, var));
556 ASSERT(insertSuccess);
557 }
558
559 return insRes;
560 }
561
MergeBindings(const VariableMap & bindings)562 void GlobalScope::MergeBindings([[maybe_unused]] const VariableMap &bindings)
563 {
564 UNREACHABLE();
565 }
566
EraseBinding(const util::StringView & name)567 Scope::VariableMap::size_type GlobalScope::EraseBinding(const util::StringView &name)
568 {
569 const auto erased = Scope::EraseBinding(name);
570 if (erased != 0) {
571 [[maybe_unused]] const auto erasedForeign = foreignBindings_.erase(name);
572 ASSERT(erasedForeign != 0);
573 }
574
575 return erased;
576 }
577
InsertForeignBinding(const util::StringView & name,Variable * const var)578 Scope::InsertResult GlobalScope::InsertForeignBinding(const util::StringView &name, Variable *const var)
579 {
580 return GlobalScope::InsertImpl(name, var, true, false);
581 }
582
InsertImpl(const util::StringView & name,Variable * const var,const bool isForeign,const bool isDynamic)583 Scope::InsertResult GlobalScope::InsertImpl(const util::StringView &name, Variable *const var, const bool isForeign,
584 const bool isDynamic)
585 {
586 if (!isDynamic && isForeign && !var->Declaration()->Name().Is(compiler::Signatures::ETS_GLOBAL)) {
587 const auto *const node = var->Declaration()->Node();
588
589 if (!(node->IsExported() || node->IsDefaultExported() || node->IsExportedType())) {
590 return Scope::InsertResult {Bindings().end(), false};
591 }
592 }
593
594 const auto insRes = Scope::InsertBinding(name, var);
595 if (insRes.second) {
596 [[maybe_unused]] const bool insertSuccess = std::get<1>(foreignBindings_.emplace(name, isForeign));
597 ASSERT(insertSuccess);
598 }
599
600 return insRes;
601 }
602
IsForeignBinding(const util::StringView & name) const603 bool GlobalScope::IsForeignBinding(const util::StringView &name) const
604 {
605 // Asserts make sure that the passed in key comes from this scope
606 ASSERT(Bindings().find(name) != Bindings().end());
607 ASSERT(foreignBindings_.find(name) != foreignBindings_.end());
608
609 return foreignBindings_.at(name);
610 }
611
InsertDynamicBinding(const util::StringView & name,Variable * const var)612 Scope::InsertResult GlobalScope::InsertDynamicBinding(const util::StringView &name, Variable *const var)
613 {
614 return InsertImpl(name, var, true, true);
615 }
616
617 // ModuleScope
618
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)619 Variable *ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
620 [[maybe_unused]] ScriptExtension extension)
621 {
622 switch (newDecl->Type()) {
623 case DeclType::VAR: {
624 return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
625 }
626 case DeclType::FUNC: {
627 return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
628 }
629 case DeclType::ENUM: {
630 return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
631 }
632 case DeclType::ENUM_LITERAL: {
633 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
634 }
635 case DeclType::INTERFACE: {
636 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
637 }
638 case DeclType::IMPORT: {
639 return AddImport(allocator, currentVariable, newDecl);
640 }
641 case DeclType::EXPORT: {
642 return allocator->New<LocalVariable>(newDecl, VariableFlags::NONE);
643 }
644 default: {
645 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
646 }
647 }
648 }
649
AddImportDecl(ir::ImportDeclaration * importDecl,ImportDeclList && decls)650 void ModuleScope::AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls)
651 {
652 auto res = imports_.emplace_back(importDecl, decls);
653
654 for (auto &decl : res.second) {
655 decl->BindNode(importDecl);
656 }
657 }
658
AddExportDecl(ir::AstNode * exportDecl,ExportDecl * decl)659 void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl)
660 {
661 decl->BindNode(exportDecl);
662
663 ArenaVector<ExportDecl *> decls(allocator_->Adapter());
664 decls.push_back(decl);
665
666 AddExportDecl(exportDecl, std::move(decls));
667 }
668
AddExportDecl(ir::AstNode * exportDecl,ExportDeclList && decls)669 void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls)
670 {
671 auto res = exports_.emplace_back(exportDecl, decls);
672
673 for (auto &decl : res.second) {
674 decl->BindNode(exportDecl);
675 }
676 }
677
AddImport(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)678 Variable *ModuleScope::AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
679 {
680 if (currentVariable != nullptr && currentVariable->Declaration()->Type() != DeclType::VAR) {
681 return nullptr;
682 }
683
684 if (newDecl->Node()->IsImportNamespaceSpecifier()) {
685 return InsertBinding(newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::READONLY))
686 .first->second;
687 }
688
689 auto *variable = allocator->New<ModuleVariable>(newDecl, VariableFlags::NONE);
690 variable->ExoticName() = newDecl->AsImportDecl()->ImportName();
691 InsertBinding(newDecl->Name(), variable);
692 return variable;
693 }
694
ExportAnalysis()695 bool ModuleScope::ExportAnalysis()
696 {
697 std::set<util::StringView> exportedNames;
698
699 for (const auto &[exportDecl, decls] : exports_) {
700 if (exportDecl->IsExportAllDeclaration()) {
701 const auto *exportAllDecl = exportDecl->AsExportAllDeclaration();
702
703 if (exportAllDecl->Exported() == nullptr) {
704 continue;
705 }
706
707 auto result = exportedNames.insert(exportAllDecl->Exported()->Name());
708 if (!result.second) {
709 return false;
710 }
711
712 continue;
713 }
714
715 if (exportDecl->IsExportNamedDeclaration()) {
716 const auto *exportNamedDecl = exportDecl->AsExportNamedDeclaration();
717
718 if (exportNamedDecl->Source() != nullptr) {
719 continue;
720 }
721 }
722
723 for (const auto *decl : decls) {
724 varbinder::Variable *variable = FindLocal(decl->LocalName(), varbinder::ResolveBindingOptions::BINDINGS);
725
726 if (variable == nullptr) {
727 continue;
728 }
729
730 auto result = exportedNames.insert(decl->ExportName());
731 if (!result.second) {
732 return false;
733 }
734
735 if (!variable->IsModuleVariable()) {
736 variable->AddFlag(VariableFlags::LOCAL_EXPORT);
737 localExports_.insert({variable, decl->ExportName()});
738 }
739 }
740 }
741
742 return true;
743 }
744
FindLocal(const util::StringView & name,ResolveBindingOptions options) const745 Variable *FunctionScope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
746 {
747 if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) {
748 auto found = typeAliasScope_->Bindings().find(name);
749 if (found != typeAliasScope_->Bindings().end()) {
750 return found->second;
751 }
752 }
753
754 if ((options & ResolveBindingOptions::ALL_NON_TYPE) == 0) {
755 return nullptr;
756 }
757
758 if ((options & ResolveBindingOptions::INTERFACES) != 0) {
759 std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name);
760 util::StringView interfaceNameView(tsBindingName);
761
762 auto res = Bindings().find(interfaceNameView);
763 if (res != Bindings().end()) {
764 return res->second;
765 }
766
767 if ((options & ResolveBindingOptions::BINDINGS) == 0) {
768 return nullptr;
769 }
770 }
771
772 auto res = Bindings().find(name);
773 if (res == Bindings().end()) {
774 return nullptr;
775 }
776
777 return res->second;
778 }
779
780 // LocalScope
781
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)782 Variable *LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
783 [[maybe_unused]] ScriptExtension extension)
784 {
785 return AddLocal(allocator, currentVariable, newDecl, extension);
786 }
787
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)788 Variable *LocalScopeWithTypeAlias::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
789 [[maybe_unused]] ScriptExtension extension)
790 {
791 if (newDecl->IsTypeAliasDecl()) {
792 auto *ident = newDecl->Node()->AsTSTypeAliasDeclaration()->Id();
793 auto *var = typeAliasScope_->AddBinding(allocator, currentVariable, newDecl, extension);
794 if (var != nullptr) {
795 var->SetScope(this);
796 if (ident != nullptr) {
797 ident->SetVariable(var);
798 }
799 }
800 return var;
801 }
802 return AddLocal(allocator, currentVariable, newDecl, extension);
803 }
804
FindLocal(const util::StringView & name,ResolveBindingOptions options) const805 Variable *LocalScopeWithTypeAlias::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
806 {
807 if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) {
808 auto found = typeAliasScope_->Bindings().find(name);
809 if (found != typeAliasScope_->Bindings().end()) {
810 return found->second;
811 }
812 }
813
814 if ((options & ResolveBindingOptions::ALL_NON_TYPE) == 0) {
815 return nullptr;
816 }
817
818 if ((options & ResolveBindingOptions::INTERFACES) != 0) {
819 std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name);
820 util::StringView interfaceNameView(tsBindingName);
821
822 auto res = Bindings().find(interfaceNameView);
823 if (res != Bindings().end()) {
824 return res->second;
825 }
826
827 if ((options & ResolveBindingOptions::BINDINGS) == 0) {
828 return nullptr;
829 }
830 }
831
832 auto res = Bindings().find(name);
833 if (res == Bindings().end()) {
834 return nullptr;
835 }
836
837 return res->second;
838 }
839
FindLocal(const util::StringView & name,ResolveBindingOptions options) const840 Variable *ClassScope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
841 {
842 if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) {
843 auto found = TypeAliasScope()->Bindings().find(name);
844 if (found != TypeAliasScope()->Bindings().end()) {
845 return found->second;
846 }
847 }
848
849 if ((options & ResolveBindingOptions::VARIABLES) != 0) {
850 auto found = instanceFieldScope_->Bindings().find(name);
851 if (found != instanceFieldScope_->Bindings().end()) {
852 return found->second;
853 }
854 }
855
856 if ((options & ResolveBindingOptions::STATIC_VARIABLES) != 0) {
857 auto found = staticFieldScope_->Bindings().find(name);
858 if (found != staticFieldScope_->Bindings().end()) {
859 return found->second;
860 }
861 }
862
863 if ((options & ResolveBindingOptions::DECLARATION) != 0) {
864 auto found = instanceDeclScope_->Bindings().find(name);
865 if (found != instanceDeclScope_->Bindings().end()) {
866 return found->second;
867 }
868 }
869
870 if ((options & ResolveBindingOptions::STATIC_DECLARATION) != 0) {
871 auto found = staticDeclScope_->Bindings().find(name);
872 if (found != staticDeclScope_->Bindings().end()) {
873 return found->second;
874 }
875 }
876
877 if ((options & ResolveBindingOptions::METHODS) != 0) {
878 auto found = instanceMethodScope_->Bindings().find(name);
879 if (found != instanceMethodScope_->Bindings().end()) {
880 return found->second;
881 }
882 }
883
884 if ((options & ResolveBindingOptions::STATIC_METHODS) != 0) {
885 auto found = staticMethodScope_->Bindings().find(name);
886 if (found != staticMethodScope_->Bindings().end()) {
887 return found->second;
888 }
889 }
890
891 return nullptr;
892 }
893
SetBindingProps(Decl * newDecl,BindingProps * props,bool isStatic)894 void ClassScope::SetBindingProps(Decl *newDecl, BindingProps *props, bool isStatic)
895 {
896 switch (newDecl->Type()) {
897 case DeclType::CONST:
898 case DeclType::READONLY:
899 case DeclType::LET: {
900 props->SetBindingProps(VariableFlags::PROPERTY, newDecl->Node()->AsClassProperty()->Id(),
901 isStatic ? staticFieldScope_ : instanceFieldScope_);
902 break;
903 }
904 case DeclType::INTERFACE: {
905 props->SetBindingProps(VariableFlags::INTERFACE, newDecl->Node()->AsTSInterfaceDeclaration()->Id(),
906 isStatic ? staticDeclScope_ : instanceDeclScope_);
907 break;
908 }
909 case DeclType::CLASS: {
910 props->SetBindingProps(VariableFlags::CLASS, newDecl->Node()->AsClassDefinition()->Ident(),
911 isStatic ? staticDeclScope_ : instanceDeclScope_);
912 break;
913 }
914 case DeclType::ENUM_LITERAL: {
915 props->SetBindingProps(VariableFlags::ENUM_LITERAL, newDecl->Node()->AsTSEnumDeclaration()->Key(),
916 isStatic ? staticDeclScope_ : instanceDeclScope_);
917 break;
918 }
919 case DeclType::TYPE_ALIAS: {
920 props->SetBindingProps(VariableFlags::TYPE_ALIAS, newDecl->Node()->AsTSTypeAliasDeclaration()->Id(),
921 TypeAliasScope());
922 break;
923 }
924 case DeclType::ANNOTATIONDECL: {
925 props->SetBindingProps(VariableFlags::ANNOTATIONDECL,
926 newDecl->Node()->AsAnnotationDeclaration()->GetBaseName(),
927 isStatic ? staticDeclScope_ : instanceDeclScope_);
928 break;
929 }
930 case DeclType::ANNOTATIONUSAGE: {
931 props->SetBindingProps(VariableFlags::ANNOTATIONUSAGE, newDecl->Node()->AsAnnotationUsage()->GetBaseName(),
932 isStatic ? staticDeclScope_ : instanceDeclScope_);
933 break;
934 }
935 default: {
936 UNREACHABLE();
937 break;
938 }
939 }
940 }
941
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)942 Variable *ClassScope::AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl,
943 [[maybe_unused]] ScriptExtension extension)
944 {
945 bool isStatic = newDecl->Node()->IsStatic();
946 BindingProps props;
947
948 if (isStatic) {
949 props.SetFlagsType(VariableFlags::STATIC);
950 }
951
952 SetBindingProps(newDecl, &props, isStatic);
953
954 auto options = newDecl->Type() != DeclType::TYPE_ALIAS ? ResolveBindingOptions::ALL_NON_TYPE
955 : ResolveBindingOptions::TYPE_ALIASES;
956
957 const auto *foundVar = FindLocal(newDecl->Name(), options);
958 if (foundVar != nullptr) {
959 if (!newDecl->IsLetOrConstDecl()) {
960 return nullptr;
961 }
962
963 foundVar = FindLocal(newDecl->Name(),
964 ResolveBindingOptions::ALL ^ (isStatic ? ResolveBindingOptions::VARIABLES
965 : ResolveBindingOptions::STATIC_VARIABLES));
966 if (foundVar != nullptr) {
967 return nullptr;
968 }
969 }
970
971 auto *var = props.GetTargetScope()->AddBinding(allocator, nullptr, newDecl, extension);
972 if (var == nullptr) {
973 return nullptr;
974 }
975
976 if (auto node = newDecl->Node();
977 node->IsStatement() &&
978 (node->AsStatement()->IsMethodDefinition() || node->IsClassProperty() || node->IsClassStaticBlock()) &&
979 node->AsStatement()->AsClassElement()->Value() != nullptr) {
980 props.SetFlagsType(VariableFlags::INITIALIZED);
981 }
982
983 var->SetScope(this);
984 var->AddFlag(props.GetFlags());
985
986 if (props.GetIdent() != nullptr) {
987 props.GetIdent()->SetVariable(var);
988 }
989
990 return var;
991 }
992
ConvertToVariableScope(ArenaAllocator * allocator)993 void LoopDeclarationScope::ConvertToVariableScope(ArenaAllocator *allocator)
994 {
995 if (NeedLexEnv()) {
996 return;
997 }
998
999 const auto &bindings = Bindings();
1000 for (auto &[name, var] : bindings) {
1001 if (!var->LexicalBound() || !var->Declaration()->IsLetOrConstDecl()) {
1002 continue;
1003 }
1004
1005 slotIndex_++;
1006 loopType_ = ScopeType::LOOP_DECL;
1007 auto *copiedVar = var->AsLocalVariable()->Copy(allocator, var->Declaration());
1008 copiedVar->AddFlag(VariableFlags::INITIALIZED | VariableFlags::PER_ITERATION);
1009 var->AddFlag(VariableFlags::LOOP_DECL);
1010 loopScope_->InsertBinding(name, copiedVar);
1011 }
1012
1013 if (loopType_ == ScopeType::LOOP_DECL) {
1014 auto *parentVarScope = Parent()->EnclosingVariableScope();
1015 slotIndex_ = std::max(slotIndex_, parentVarScope->LexicalSlots());
1016 evalBindings_ = parentVarScope->EvalBindings();
1017 initScope_ = allocator->New<LocalScope>(allocator, Parent());
1018 initScope_->BindNode(Node());
1019 initScope_->MergeBindings(bindings);
1020 }
1021 }
1022
ConvertToVariableScope(ArenaAllocator * allocator)1023 void LoopScope::ConvertToVariableScope(ArenaAllocator *allocator)
1024 {
1025 declScope_->ConvertToVariableScope(allocator);
1026
1027 if (loopType_ != ScopeType::LOCAL) {
1028 return;
1029 }
1030
1031 for (const auto &[_, var] : Bindings()) {
1032 (void)_;
1033 if (var->LexicalBound() && var->Declaration()->IsLetDecl()) {
1034 ASSERT(declScope_->NeedLexEnv());
1035 loopType_ = ScopeType::LOOP;
1036 break;
1037 }
1038 }
1039
1040 if (loopType_ == ScopeType::LOOP) {
1041 slotIndex_ = std::max(slotIndex_, declScope_->LexicalSlots());
1042 evalBindings_ = declScope_->EvalBindings();
1043 }
1044 }
1045
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)1046 Variable *CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
1047 [[maybe_unused]] ScriptExtension extension)
1048 {
1049 return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED);
1050 }
1051
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)1052 Variable *CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
1053 [[maybe_unused]] ScriptExtension extension)
1054 {
1055 if (!newDecl->IsVarDecl() &&
1056 (paramScope_->FindLocal(newDecl->Name(), varbinder::ResolveBindingOptions::BINDINGS) != nullptr)) {
1057 return nullptr;
1058 }
1059
1060 if (newDecl->IsTypeAliasDecl()) {
1061 auto *ident = newDecl->Node()->AsTSTypeAliasDeclaration()->Id();
1062 auto *var = TypeAliasScope()->AddBinding(allocator, currentVariable, newDecl, extension);
1063 if (var != nullptr) {
1064 var->SetScope(this);
1065 if (ident != nullptr) {
1066 ident->SetVariable(var);
1067 }
1068 }
1069 return var;
1070 }
1071
1072 return AddLocal(allocator, currentVariable, newDecl, extension);
1073 }
1074 } // namespace ark::es2panda::varbinder
1075