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 "compiler/core/compilerContext.h"
41 #include "macros.h"
42 #include "util/ustring.h"
43 #include "generated/signatures.h"
44
45 namespace panda::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
FindLocal(const util::StringView & name,ResolveBindingOptions options) const76 Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
77 {
78 if ((options & ResolveBindingOptions::INTERFACES) != 0) {
79 std::string tsBindingName = varbinder::TSBinding::ToTSBinding(name);
80 util::StringView interfaceNameView(tsBindingName);
81
82 auto res = bindings_.find(interfaceNameView);
83 if (res != bindings_.end()) {
84 return res->second;
85 }
86
87 if ((options & ResolveBindingOptions::BINDINGS) == 0) {
88 return nullptr;
89 }
90 }
91
92 auto res = bindings_.find(name);
93 if (res == bindings_.end()) {
94 return nullptr;
95 }
96
97 return res->second;
98 }
99
InsertBinding(const util::StringView & name,Variable * const var)100 Scope::InsertResult Scope::InsertBinding(const util::StringView &name, Variable *const var)
101 {
102 ASSERT(var != nullptr);
103 return bindings_.emplace(name, var);
104 }
105
TryInsertBinding(const util::StringView & name,Variable * const var)106 Scope::InsertResult Scope::TryInsertBinding(const util::StringView &name, Variable *const var)
107 {
108 ASSERT(var != nullptr);
109 return bindings_.try_emplace(name, var);
110 }
111
ReplaceBindings(VariableMap bindings)112 void Scope::ReplaceBindings(VariableMap bindings)
113 {
114 bindings_ = std::move(bindings);
115 }
116
EraseBinding(const util::StringView & name)117 Scope::VariableMap::size_type Scope::EraseBinding(const util::StringView &name)
118 {
119 return bindings_.erase(name);
120 }
121
FindInGlobal(const util::StringView & name,const ResolveBindingOptions options) const122 ConstScopeFindResult Scope::FindInGlobal(const util::StringView &name, const ResolveBindingOptions options) const
123 {
124 const auto *scopeIter = this;
125 const auto *scopeParent = this->Parent();
126 // One scope below true global is ETSGLOBAL
127 while (scopeParent != nullptr && !scopeParent->IsGlobalScope()) {
128 scopeIter = scopeParent;
129 scopeParent = scopeIter->Parent();
130 }
131
132 auto *resolved = scopeIter->FindLocal(name, options);
133 if (resolved == nullptr && scopeParent != nullptr) {
134 // If the variable cannot be found in the scope of the local ETSGLOBAL, than we still need to check the true
135 // global scope which contains all the imported ETSGLOBALs
136 resolved = scopeParent->FindLocal(name, options);
137 }
138
139 return {name, scopeIter, 0, 0, resolved};
140 }
141
FindInFunctionScope(const util::StringView & name,const ResolveBindingOptions options) const142 ConstScopeFindResult Scope::FindInFunctionScope(const util::StringView &name, const ResolveBindingOptions options) const
143 {
144 const auto *scopeIter = this;
145 while (scopeIter != nullptr && !scopeIter->IsClassScope() && !scopeIter->IsGlobalScope()) {
146 if (auto *const resolved = scopeIter->FindLocal(name, options); resolved != nullptr) {
147 return {name, scopeIter, 0, 0, resolved};
148 }
149 scopeIter = scopeIter->Parent();
150 }
151
152 return {name, scopeIter, 0, 0, nullptr};
153 }
154
Find(const util::StringView & name,const ResolveBindingOptions options)155 ScopeFindResult Scope::Find(const util::StringView &name, const ResolveBindingOptions options)
156 {
157 return FindImpl<ScopeFindResult>(this, name, options);
158 }
159
Find(const util::StringView & name,const ResolveBindingOptions options) const160 ConstScopeFindResult Scope::Find(const util::StringView &name, const ResolveBindingOptions options) const
161 {
162 return FindImpl<ConstScopeFindResult>(this, name, options);
163 }
164
FindDecl(const util::StringView & name) const165 Decl *Scope::FindDecl(const util::StringView &name) const
166 {
167 for (auto *it : decls_) {
168 if (it->Name() == name) {
169 return it;
170 }
171 }
172
173 return nullptr;
174 }
175
IterateShadowedVariables(const util::StringView & name,const VariableVisitor & visitor)176 std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitor &visitor)
177 {
178 auto *iter = this;
179
180 while (iter != nullptr) {
181 auto *v = iter->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS);
182
183 if (v != nullptr && visitor(v)) {
184 return {iter, true};
185 }
186
187 if (iter->IsFunctionVariableScope()) {
188 break;
189 }
190
191 iter = iter->Parent();
192 }
193
194 return {iter, false};
195 }
196
AddLocalVar(ArenaAllocator * allocator,Decl * newDecl)197 Variable *Scope::AddLocalVar(ArenaAllocator *allocator, Decl *newDecl)
198 {
199 auto [scope, shadowed] =
200 IterateShadowedVariables(newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
201
202 if (shadowed) {
203 return nullptr;
204 }
205
206 VariableFlags varFlags = VariableFlags::HOIST_VAR | VariableFlags::LEXICAL_VAR;
207 if (scope->IsGlobalScope()) {
208 return scope->InsertBinding(newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)).first->second;
209 }
210
211 return scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags);
212 }
213
AddLocal(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)214 Variable *Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
215 [[maybe_unused]] ScriptExtension extension)
216 {
217 VariableFlags flags = VariableFlags::LEXICAL;
218 switch (newDecl->Type()) {
219 case DeclType::VAR: {
220 return AddLocalVar(allocator, newDecl);
221 }
222 case DeclType::ENUM: {
223 return bindings_.insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)}).first->second;
224 }
225 case DeclType::ENUM_LITERAL: {
226 return bindings_
227 .insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::ENUM_LITERAL)})
228 .first->second;
229 }
230 case DeclType::INTERFACE: {
231 return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)})
232 .first->second;
233 }
234 case DeclType::TYPE_PARAMETER: {
235 return bindings_
236 .insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::TYPE_PARAMETER)})
237 .first->second;
238 }
239 case DeclType::FUNC: {
240 flags = VariableFlags::HOIST;
241 [[fallthrough]];
242 }
243 default: {
244 if (currentVariable != nullptr) {
245 return nullptr;
246 }
247
248 auto [_, shadowed] = IterateShadowedVariables(
249 newDecl->Name(), [](const Variable *v) { return v->HasFlag(VariableFlags::LEXICAL_VAR); });
250 (void)_;
251
252 if (shadowed) {
253 return nullptr;
254 }
255
256 return bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)}).first->second;
257 }
258 }
259 }
260
CheckDirectEval(compiler::CompilerContext * compilerCtx)261 void VariableScope::CheckDirectEval(compiler::CompilerContext *compilerCtx)
262 {
263 ASSERT(compilerCtx);
264 const auto &varMap = Bindings();
265
266 if (!HasFlag(ScopeFlags::NO_REG_STORE) || varMap.empty()) {
267 evalBindings_ = compiler::INVALID_LITERAL_BUFFER_ID;
268 return;
269 }
270
271 size_t constBindings = 0;
272 for (const auto &[name, var] : varMap) {
273 (void)name;
274 var->SetLexical(this);
275
276 if (var->LexicalBound() && var->Declaration()->IsConstDecl()) {
277 constBindings++;
278 }
279 }
280
281 std::vector<compiler::Literal> literals(LexicalSlots() + constBindings, compiler::Literal(util::StringView()));
282
283 if (constBindings == 0U) {
284 for (const auto &[name, variable] : varMap) {
285 if (!variable->LexicalBound()) {
286 continue;
287 }
288
289 literals[variable->AsLocalVariable()->LexIdx()] = compiler::Literal(name);
290 }
291 } else {
292 std::vector<varbinder::Variable *> bindings(LexicalSlots());
293
294 for (const auto &[name, variable] : varMap) {
295 (void)name;
296 if (!variable->LexicalBound()) {
297 continue;
298 }
299
300 bindings[variable->AsLocalVariable()->LexIdx()] = variable;
301 }
302
303 uint32_t buffIndex = 0;
304 for (const auto *variable : bindings) {
305 if (variable == nullptr) {
306 ASSERT(literals[buffIndex].GetString().empty());
307 buffIndex++;
308 continue;
309 }
310 if (variable->Declaration()->IsConstDecl()) {
311 literals[buffIndex++] = compiler::Literal(true);
312 }
313 literals[buffIndex++] = compiler::Literal(variable->Name());
314 }
315 }
316
317 evalBindings_ = compilerCtx->AddContextLiteral(std::move(literals));
318 }
319
AddParam(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,VariableFlags flags)320 Variable *ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)
321 {
322 ASSERT(newDecl->IsParameterDecl());
323
324 if (currentVariable != nullptr) {
325 return nullptr;
326 }
327
328 auto *param = allocator->New<LocalVariable>(newDecl, flags);
329
330 params_.push_back(param);
331 InsertBinding(newDecl->Name(), param);
332 return param;
333 }
334
AddParamDecl(ArenaAllocator * allocator,ir::AstNode * param)335 std::tuple<ParameterDecl *, ir::AstNode *, Variable *> ParamScope::AddParamDecl(ArenaAllocator *allocator,
336 ir::AstNode *param)
337 {
338 const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size());
339
340 auto *decl = NewDecl<ParameterDecl>(allocator, name);
341 auto *var = AddParam(allocator, FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS), decl,
342 VariableFlags::VAR | VariableFlags::LOCAL);
343
344 if (var == nullptr) {
345 return {decl, param, nullptr};
346 }
347
348 if (!pattern) {
349 decl->BindNode(param);
350 return {decl, nullptr, var};
351 }
352
353 std::vector<ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param);
354
355 for (auto *binding : bindings) {
356 auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name());
357 varDecl->BindNode(binding);
358
359 if (FindLocal(varDecl->Name(), varbinder::ResolveBindingOptions::BINDINGS) != nullptr) {
360 return {decl, binding, nullptr};
361 }
362
363 auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR | VariableFlags::LOCAL);
364 TryInsertBinding(varDecl->Name(), paramVar);
365 }
366
367 return {decl, nullptr, var};
368 }
369
BindName(ArenaAllocator * allocator,util::StringView name)370 void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name)
371 {
372 nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED);
373 if (!functionScope_->InsertBinding(name, nameVar_).second) {
374 nameVar_ = nullptr;
375 }
376 }
377
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)378 Variable *FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
379 [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
380 [[maybe_unused]] ScriptExtension extension)
381 {
382 UNREACHABLE();
383 }
384
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)385 Variable *FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
386 [[maybe_unused]] ScriptExtension extension)
387 {
388 switch (newDecl->Type()) {
389 case DeclType::VAR: {
390 return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
391 }
392 case DeclType::FUNC: {
393 return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
394 }
395 case DeclType::ENUM: {
396 return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
397 }
398 case DeclType::ENUM_LITERAL: {
399 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
400 }
401 case DeclType::INTERFACE: {
402 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
403 }
404 default: {
405 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
406 }
407 }
408 }
409
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)410 Variable *GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
411 [[maybe_unused]] ScriptExtension extension)
412 {
413 switch (newDecl->Type()) {
414 case DeclType::VAR: {
415 return AddVar<GlobalVariable>(allocator, currentVariable, newDecl);
416 }
417 case DeclType::FUNC: {
418 return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension);
419 }
420 case DeclType::ENUM: {
421 return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
422 }
423 case DeclType::ENUM_LITERAL: {
424 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
425 }
426 case DeclType::INTERFACE: {
427 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
428 }
429 default: {
430 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
431 }
432 }
433 }
434
InsertBinding(const util::StringView & name,Variable * const var)435 Scope::InsertResult GlobalScope::InsertBinding(const util::StringView &name, Variable *const var)
436 {
437 return GlobalScope::InsertImpl(name, var, false, false);
438 }
439
TryInsertBinding(const util::StringView & name,Variable * const var)440 Scope::InsertResult GlobalScope::TryInsertBinding(const util::StringView &name, Variable *const var)
441 {
442 const auto insRes = Scope::TryInsertBinding(name, var);
443 if (insRes.second) {
444 [[maybe_unused]] const bool insertSuccess = std::get<1>(foreignBindings_.try_emplace(name, var));
445 ASSERT(insertSuccess);
446 }
447
448 return insRes;
449 }
450
ReplaceBindings(const VariableMap bindings)451 void GlobalScope::ReplaceBindings([[maybe_unused]] const VariableMap bindings)
452 {
453 UNREACHABLE();
454 }
455
EraseBinding(const util::StringView & name)456 Scope::VariableMap::size_type GlobalScope::EraseBinding(const util::StringView &name)
457 {
458 const auto erased = Scope::EraseBinding(name);
459 if (erased != 0) {
460 [[maybe_unused]] const auto erasedForeign = foreignBindings_.erase(name);
461 ASSERT(erasedForeign != 0);
462 }
463
464 return erased;
465 }
466
InsertForeignBinding(const util::StringView & name,Variable * const var)467 Scope::InsertResult GlobalScope::InsertForeignBinding(const util::StringView &name, Variable *const var)
468 {
469 return GlobalScope::InsertImpl(name, var, true, false);
470 }
471
InsertImpl(const util::StringView & name,Variable * const var,const bool isForeign,const bool isDynamic)472 Scope::InsertResult GlobalScope::InsertImpl(const util::StringView &name, Variable *const var, const bool isForeign,
473 const bool isDynamic)
474 {
475 if (!isDynamic && isForeign && !var->Declaration()->Name().Is(compiler::Signatures::ETS_GLOBAL)) {
476 const auto *const node = var->Declaration()->Node();
477
478 if (!(node->IsExported() || node->IsDefaultExported())) {
479 return Scope::InsertResult {Bindings().end(), false};
480 }
481 }
482
483 const auto insRes = Scope::InsertBinding(name, var);
484 if (insRes.second) {
485 [[maybe_unused]] const bool insertSuccess = std::get<1>(foreignBindings_.emplace(name, isForeign));
486 ASSERT(insertSuccess);
487 }
488
489 return insRes;
490 }
491
IsForeignBinding(const util::StringView & name) const492 bool GlobalScope::IsForeignBinding(const util::StringView &name) const
493 {
494 // Asserts make sure that the passed in key comes from this scope
495 ASSERT(Bindings().find(name) != Bindings().end());
496 ASSERT(foreignBindings_.find(name) != foreignBindings_.end());
497
498 return foreignBindings_.at(name);
499 }
500
InsertDynamicBinding(const util::StringView & name,Variable * const var)501 Scope::InsertResult GlobalScope::InsertDynamicBinding(const util::StringView &name, Variable *const var)
502 {
503 return InsertImpl(name, var, true, true);
504 }
505
506 // ModuleScope
507
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)508 Variable *ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
509 [[maybe_unused]] ScriptExtension extension)
510 {
511 switch (newDecl->Type()) {
512 case DeclType::VAR: {
513 return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
514 }
515 case DeclType::FUNC: {
516 return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
517 }
518 case DeclType::ENUM: {
519 return InsertBinding(newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)).first->second;
520 }
521 case DeclType::ENUM_LITERAL: {
522 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
523 }
524 case DeclType::INTERFACE: {
525 return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
526 }
527 case DeclType::IMPORT: {
528 return AddImport(allocator, currentVariable, newDecl);
529 }
530 case DeclType::EXPORT: {
531 return allocator->New<LocalVariable>(newDecl, VariableFlags::NONE);
532 }
533 default: {
534 return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
535 }
536 }
537 }
538
AddImportDecl(ir::ImportDeclaration * importDecl,ImportDeclList && decls)539 void ModuleScope::AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls)
540 {
541 auto res = imports_.emplace_back(importDecl, decls);
542
543 for (auto &decl : res.second) {
544 decl->BindNode(importDecl);
545 }
546 }
547
AddExportDecl(ir::AstNode * exportDecl,ExportDecl * decl)548 void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl)
549 {
550 decl->BindNode(exportDecl);
551
552 ArenaVector<ExportDecl *> decls(allocator_->Adapter());
553 decls.push_back(decl);
554
555 AddExportDecl(exportDecl, std::move(decls));
556 }
557
AddExportDecl(ir::AstNode * exportDecl,ExportDeclList && decls)558 void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls)
559 {
560 auto res = exports_.emplace_back(exportDecl, decls);
561
562 for (auto &decl : res.second) {
563 decl->BindNode(exportDecl);
564 }
565 }
566
AddImport(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl)567 Variable *ModuleScope::AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
568 {
569 if (currentVariable != nullptr && currentVariable->Declaration()->Type() != DeclType::VAR) {
570 return nullptr;
571 }
572
573 if (newDecl->Node()->IsImportNamespaceSpecifier()) {
574 return InsertBinding(newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::READONLY))
575 .first->second;
576 }
577
578 auto *variable = allocator->New<ModuleVariable>(newDecl, VariableFlags::NONE);
579 variable->ExoticName() = newDecl->AsImportDecl()->ImportName();
580 InsertBinding(newDecl->Name(), variable);
581 return variable;
582 }
583
ExportAnalysis()584 bool ModuleScope::ExportAnalysis()
585 {
586 std::set<util::StringView> exportedNames;
587
588 for (const auto &[exportDecl, decls] : exports_) {
589 if (exportDecl->IsExportAllDeclaration()) {
590 const auto *exportAllDecl = exportDecl->AsExportAllDeclaration();
591
592 if (exportAllDecl->Exported() == nullptr) {
593 continue;
594 }
595
596 auto result = exportedNames.insert(exportAllDecl->Exported()->Name());
597 if (!result.second) {
598 return false;
599 }
600
601 continue;
602 }
603
604 if (exportDecl->IsExportNamedDeclaration()) {
605 const auto *exportNamedDecl = exportDecl->AsExportNamedDeclaration();
606
607 if (exportNamedDecl->Source() != nullptr) {
608 continue;
609 }
610 }
611
612 for (const auto *decl : decls) {
613 varbinder::Variable *variable = FindLocal(decl->LocalName(), varbinder::ResolveBindingOptions::BINDINGS);
614
615 if (variable == nullptr) {
616 continue;
617 }
618
619 auto result = exportedNames.insert(decl->ExportName());
620 if (!result.second) {
621 return false;
622 }
623
624 if (!variable->IsModuleVariable()) {
625 variable->AddFlag(VariableFlags::LOCAL_EXPORT);
626 localExports_.insert({variable, decl->ExportName()});
627 }
628 }
629 }
630
631 return true;
632 }
633
634 // LocalScope
635
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)636 Variable *LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
637 [[maybe_unused]] ScriptExtension extension)
638 {
639 return AddLocal(allocator, currentVariable, newDecl, extension);
640 }
641
FindLocal(const util::StringView & name,ResolveBindingOptions options) const642 Variable *ClassScope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
643 {
644 if ((options & ResolveBindingOptions::TYPE_ALIASES) != 0) {
645 auto found = typeAliasScope_->Bindings().find(name);
646 if (found != typeAliasScope_->Bindings().end()) {
647 return found->second;
648 }
649 }
650
651 if ((options & ResolveBindingOptions::VARIABLES) != 0) {
652 auto found = instanceFieldScope_->Bindings().find(name);
653 if (found != instanceFieldScope_->Bindings().end()) {
654 return found->second;
655 }
656 }
657
658 if ((options & ResolveBindingOptions::STATIC_VARIABLES) != 0) {
659 auto found = staticFieldScope_->Bindings().find(name);
660 if (found != staticFieldScope_->Bindings().end()) {
661 return found->second;
662 }
663 }
664
665 if ((options & ResolveBindingOptions::DECLARATION) != 0) {
666 auto found = instanceDeclScope_->Bindings().find(name);
667 if (found != instanceDeclScope_->Bindings().end()) {
668 return found->second;
669 }
670 }
671
672 if ((options & ResolveBindingOptions::STATIC_DECLARATION) != 0) {
673 auto found = staticDeclScope_->Bindings().find(name);
674 if (found != staticDeclScope_->Bindings().end()) {
675 return found->second;
676 }
677 }
678
679 if ((options & ResolveBindingOptions::METHODS) != 0) {
680 auto found = instanceMethodScope_->Bindings().find(name);
681 if (found != instanceMethodScope_->Bindings().end()) {
682 return found->second;
683 }
684 }
685
686 if ((options & ResolveBindingOptions::STATIC_METHODS) != 0) {
687 auto found = staticMethodScope_->Bindings().find(name);
688 if (found != staticMethodScope_->Bindings().end()) {
689 return found->second;
690 }
691 }
692
693 return nullptr;
694 }
695
SetBindingProps(Decl * newDecl,BindingProps * props,bool isStatic)696 void ClassScope::SetBindingProps(Decl *newDecl, BindingProps *props, bool isStatic)
697 {
698 switch (newDecl->Type()) {
699 case DeclType::CONST:
700 case DeclType::LET: {
701 props->SetBindingProps(VariableFlags::PROPERTY, newDecl->Node()->AsClassProperty()->Id(),
702 isStatic ? staticFieldScope_ : instanceFieldScope_);
703 break;
704 }
705 case DeclType::INTERFACE: {
706 props->SetBindingProps(VariableFlags::INTERFACE, newDecl->Node()->AsTSInterfaceDeclaration()->Id(),
707 isStatic ? staticDeclScope_ : instanceDeclScope_);
708 break;
709 }
710 case DeclType::CLASS: {
711 props->SetBindingProps(VariableFlags::CLASS, newDecl->Node()->AsClassDefinition()->Ident(),
712 isStatic ? staticDeclScope_ : instanceDeclScope_);
713 break;
714 }
715 case DeclType::ENUM_LITERAL: {
716 props->SetBindingProps(VariableFlags::ENUM_LITERAL, newDecl->Node()->AsTSEnumDeclaration()->Key(),
717 isStatic ? staticDeclScope_ : instanceDeclScope_);
718 break;
719 }
720 case DeclType::TYPE_ALIAS: {
721 props->SetBindingProps(VariableFlags::TYPE_ALIAS, newDecl->Node()->AsTSTypeAliasDeclaration()->Id(),
722 typeAliasScope_);
723 break;
724 }
725 default: {
726 UNREACHABLE();
727 break;
728 }
729 }
730 }
731
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)732 Variable *ClassScope::AddBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl,
733 [[maybe_unused]] ScriptExtension extension)
734 {
735 bool isStatic = newDecl->Node()->IsStatic();
736 BindingProps props;
737
738 if (isStatic) {
739 props.SetFlagsType(VariableFlags::STATIC);
740 }
741
742 SetBindingProps(newDecl, &props, isStatic);
743
744 const auto *foundVar = FindLocal(newDecl->Name(), ResolveBindingOptions::ALL);
745 if (foundVar != nullptr) {
746 if (!newDecl->IsLetOrConstDecl()) {
747 return nullptr;
748 }
749
750 foundVar = FindLocal(newDecl->Name(),
751 ResolveBindingOptions::ALL ^ (isStatic ? ResolveBindingOptions::VARIABLES
752 : ResolveBindingOptions::STATIC_VARIABLES));
753 if (foundVar != nullptr) {
754 return nullptr;
755 }
756 }
757
758 auto *var = props.GetTargetScope()->AddBinding(allocator, nullptr, newDecl, extension);
759 if (var == nullptr) {
760 return nullptr;
761 }
762
763 if (auto node = newDecl->Node();
764 node->IsStatement() &&
765 (node->AsStatement()->IsMethodDefinition() || node->IsClassProperty() || node->IsClassStaticBlock()) &&
766 node->AsStatement()->AsClassElement()->Value() != nullptr) {
767 props.SetFlagsType(VariableFlags::INITIALIZED);
768 }
769
770 var->SetScope(this);
771 var->AddFlag(props.GetFlags());
772
773 if (props.GetIdent() != nullptr) {
774 props.GetIdent()->SetVariable(var);
775 }
776
777 return var;
778 }
779
ConvertToVariableScope(ArenaAllocator * allocator)780 void LoopDeclarationScope::ConvertToVariableScope(ArenaAllocator *allocator)
781 {
782 if (NeedLexEnv()) {
783 return;
784 }
785
786 const auto &bindings = Bindings();
787 for (auto &[name, var] : bindings) {
788 if (!var->LexicalBound() || !var->Declaration()->IsLetOrConstDecl()) {
789 continue;
790 }
791
792 slotIndex_++;
793 loopType_ = ScopeType::LOOP_DECL;
794 auto *copiedVar = var->AsLocalVariable()->Copy(allocator, var->Declaration());
795 copiedVar->AddFlag(VariableFlags::INITIALIZED | VariableFlags::PER_ITERATION);
796 var->AddFlag(VariableFlags::LOOP_DECL);
797 loopScope_->InsertBinding(name, copiedVar);
798 }
799
800 if (loopType_ == ScopeType::LOOP_DECL) {
801 auto *parentVarScope = Parent()->EnclosingVariableScope();
802 slotIndex_ = std::max(slotIndex_, parentVarScope->LexicalSlots());
803 evalBindings_ = parentVarScope->EvalBindings();
804 initScope_ = allocator->New<LocalScope>(allocator, Parent());
805 initScope_->BindNode(Node());
806 initScope_->ReplaceBindings(bindings);
807 }
808 }
809
ConvertToVariableScope(ArenaAllocator * allocator)810 void LoopScope::ConvertToVariableScope(ArenaAllocator *allocator)
811 {
812 declScope_->ConvertToVariableScope(allocator);
813
814 if (loopType_ != ScopeType::LOCAL) {
815 return;
816 }
817
818 for (const auto &[_, var] : Bindings()) {
819 (void)_;
820 if (var->LexicalBound() && var->Declaration()->IsLetDecl()) {
821 ASSERT(declScope_->NeedLexEnv());
822 loopType_ = ScopeType::LOOP;
823 break;
824 }
825 }
826
827 if (loopType_ == ScopeType::LOOP) {
828 slotIndex_ = std::max(slotIndex_, declScope_->LexicalSlots());
829 evalBindings_ = declScope_->EvalBindings();
830 }
831 }
832
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)833 Variable *CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
834 [[maybe_unused]] ScriptExtension extension)
835 {
836 return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED);
837 }
838
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)839 Variable *CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
840 [[maybe_unused]] ScriptExtension extension)
841 {
842 if (!newDecl->IsVarDecl() &&
843 (paramScope_->FindLocal(newDecl->Name(), varbinder::ResolveBindingOptions::BINDINGS) != nullptr)) {
844 return nullptr;
845 }
846
847 return AddLocal(allocator, currentVariable, newDecl, extension);
848 }
849 } // namespace panda::es2panda::varbinder
850