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