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 #ifndef ES2PANDA_COMPILER_SCOPES_SCOPE_H
17 #define ES2PANDA_COMPILER_SCOPES_SCOPE_H
18
19 #include "varbinder/declaration.h"
20 #include "varbinder/variable.h"
21 #include "es2panda.h"
22 #include "util/enumbitops.h"
23 #include "util/ustring.h"
24
25 #include <map>
26 #include <unordered_map>
27 #include <vector>
28
29 namespace ark::es2panda::public_lib {
30 struct Context;
31 } // namespace ark::es2panda::public_lib
32
33 namespace ark::es2panda::compiler {
34 class IRNode;
35 } // namespace ark::es2panda::compiler
36
37 namespace ark::es2panda::varbinder {
38 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
39 #define DECLARE_CLASSES(type, className) class className;
40 SCOPE_TYPES(DECLARE_CLASSES)
41 #undef DECLARE_CLASSES
42
43 class Scope;
44 class VariableScope;
45 class Variable;
46
47 template <typename ScopeT,
48 std::enable_if_t<std::is_pointer_v<ScopeT> && std::is_base_of_v<Scope, std::remove_pointer_t<ScopeT>>, bool> =
49 true>
50 class ScopeFindResultT {
51 public:
52 ScopeFindResultT() = default;
ScopeFindResultT(util::StringView n, ScopeT s, uint32_t l, Variable *v)53 ScopeFindResultT(util::StringView n, ScopeT s, uint32_t l, Variable *v) : ScopeFindResultT(n, s, l, l, v) {}
ScopeFindResultT(ScopeT s, uint32_t l, uint32_t ll, Variable *v)54 ScopeFindResultT(ScopeT s, uint32_t l, uint32_t ll, Variable *v) : scope(s), level(l), lexLevel(ll), variable(v) {}
ScopeFindResultT(util::StringView n, ScopeT s, uint32_t l, uint32_t ll, Variable *v)55 ScopeFindResultT(util::StringView n, ScopeT s, uint32_t l, uint32_t ll, Variable *v)
56 : name(n), scope(s), level(l), lexLevel(ll), variable(v)
57 {
58 }
59
60 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
61 util::StringView name {};
62 ScopeT scope {};
63 uint32_t level {};
64 uint32_t lexLevel {};
65 Variable *variable {};
66 // NOLINTEND(misc-non-private-member-variables-in-classes)
67 };
68
69 using ConstScopeFindResult = ScopeFindResultT<const Scope *>;
70 using ScopeFindResult = ScopeFindResultT<Scope *>;
71
72 class Scope {
73 public:
74 virtual ~Scope() = default;
75 NO_COPY_SEMANTIC(Scope);
76 NO_MOVE_SEMANTIC(Scope);
77
78 using VariableMap = ArenaUnorderedMap<util::StringView, Variable *>;
79 using InsertResult = std::pair<VariableMap::const_iterator, bool>;
80
81 virtual ScopeType Type() const = 0;
82
83 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
84 #define DECLARE_CHECKS_CASTS(scopeType, className) \
85 bool Is##className() const \
86 { \
87 return Type() == ScopeType::scopeType; \
88 } \
89 className *As##className() \
90 { \
91 ASSERT(Is##className()); \
92 return reinterpret_cast<className *>(this); \
93 } \
94 const className *As##className() const \
95 { \
96 ASSERT(Is##className()); \
97 return reinterpret_cast<const className *>(this); \
98 }
99 SCOPE_TYPES(DECLARE_CHECKS_CASTS)
100 #undef DECLARE_CHECKS_CASTS
101
IsVariableScope() const102 bool IsVariableScope() const
103 {
104 return Type() > ScopeType::LOCAL;
105 }
106
IsFunctionVariableScope() const107 bool IsFunctionVariableScope() const
108 {
109 return Type() >= ScopeType::FUNCTION;
110 }
111
AsFunctionVariableScope()112 FunctionScope *AsFunctionVariableScope()
113 {
114 ASSERT(IsFunctionVariableScope());
115 return reinterpret_cast<FunctionScope *>(this);
116 }
117
AsFunctionVariableScope() const118 const FunctionScope *AsFunctionVariableScope() const
119 {
120 ASSERT(IsFunctionVariableScope());
121 return reinterpret_cast<const FunctionScope *>(this);
122 }
123
AsVariableScope()124 VariableScope *AsVariableScope()
125 {
126 ASSERT(IsVariableScope());
127 return reinterpret_cast<VariableScope *>(this);
128 }
129
AsVariableScope() const130 const VariableScope *AsVariableScope() const
131 {
132 ASSERT(IsVariableScope());
133 return reinterpret_cast<const VariableScope *>(this);
134 }
135
136 VariableScope *EnclosingVariableScope();
137
138 const VariableScope *EnclosingVariableScope() const;
139
140 ClassScope *EnclosingClassScope();
141 const ClassScope *EnclosingClassScope() const;
142
AddFlag(ScopeFlags flag)143 void AddFlag(ScopeFlags flag)
144 {
145 flags_ |= flag;
146 }
147
ClearFlag(ScopeFlags flag)148 void ClearFlag(ScopeFlags flag)
149 {
150 flags_ &= ~flag;
151 }
152
HasFlag(ScopeFlags flag) const153 bool HasFlag(ScopeFlags flag) const
154 {
155 return (flags_ & flag) != 0;
156 }
157
Decls()158 ArenaVector<Decl *> &Decls()
159 {
160 return decls_;
161 }
162
Decls() const163 const ArenaVector<Decl *> &Decls() const
164 {
165 return decls_;
166 }
167
SetParent(Scope *parent)168 void SetParent(Scope *parent)
169 {
170 parent_ = parent;
171 }
172
Parent()173 Scope *Parent()
174 {
175 return parent_;
176 }
177
Parent() const178 const Scope *Parent() const
179 {
180 return parent_;
181 }
182
ScopeStart() const183 const compiler::IRNode *ScopeStart() const
184 {
185 return startIns_;
186 }
187
ScopeEnd() const188 const compiler::IRNode *ScopeEnd() const
189 {
190 return endIns_;
191 }
192
SetScopeStart(const compiler::IRNode *ins)193 void SetScopeStart(const compiler::IRNode *ins)
194 {
195 startIns_ = ins;
196 }
197
SetScopeEnd(const compiler::IRNode *ins)198 void SetScopeEnd(const compiler::IRNode *ins)
199 {
200 endIns_ = ins;
201 }
202
Node()203 ir::AstNode *Node()
204 {
205 return node_;
206 }
207
Node() const208 const ir::AstNode *Node() const
209 {
210 return node_;
211 }
212
BindNode(ir::AstNode *node)213 void BindNode(ir::AstNode *node)
214 {
215 node_ = node;
216 }
217
AddDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)218 Variable *AddDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)
219 {
220 decls_.push_back(decl);
221 auto options = decl->IsTypeAliasDecl() ? varbinder::ResolveBindingOptions::TYPE_ALIASES
222 : varbinder::ResolveBindingOptions::BINDINGS;
223 return AddBinding(allocator, FindLocal(decl->Name(), options), decl, extension);
224 }
225
AddTsDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)226 Variable *AddTsDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)
227 {
228 decls_.push_back(decl);
229 return AddBinding(allocator, FindLocal(decl->Name(), ResolveBindingOptions::ALL), decl, extension);
230 }
231
232 template <typename T, typename... Args>
233 T *NewDecl(ArenaAllocator *allocator, Args &&...args);
234
235 template <typename DeclType, typename VariableType>
236 VariableType *AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags);
237
238 template <typename DeclType = varbinder::LetDecl, typename VariableType = varbinder::LocalVariable>
239 static VariableType *CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags,
240 ir::AstNode *node);
241
242 template <typename T, typename... Args>
243 Variable *PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args);
244
245 virtual InsertResult InsertBinding(const util::StringView &name, Variable *var);
246 virtual InsertResult TryInsertBinding(const util::StringView &name, Variable *var);
247 virtual void MergeBindings(VariableMap const &bindings);
248 virtual VariableMap::size_type EraseBinding(const util::StringView &name);
249
Bindings() const250 const VariableMap &Bindings() const
251 {
252 return bindings_;
253 }
254
OrderedBindings(ArenaAllocator *allocator) const255 ArenaMap<util::StringView, Variable *> OrderedBindings(ArenaAllocator *allocator) const
256 {
257 ArenaMap<util::StringView, Variable *> result(allocator->Adapter());
258 result.insert(bindings_.begin(), bindings_.end());
259 return result;
260 }
261
262 virtual Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
263 [[maybe_unused]] ScriptExtension extension) = 0;
264
265 virtual Variable *FindLocal(const util::StringView &name, ResolveBindingOptions options) const;
266
267 bool IsSuperscopeOf(const varbinder::Scope *subscope) const;
268
269 ConstScopeFindResult Find(const util::StringView &name,
270 ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
271
272 ScopeFindResult Find(const util::StringView &name, ResolveBindingOptions options = ResolveBindingOptions::BINDINGS);
273
274 ConstScopeFindResult FindInGlobal(const util::StringView &name,
275 ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
276
277 ConstScopeFindResult FindInFunctionScope(const util::StringView &name,
278 ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
279
280 Decl *FindDecl(const util::StringView &name) const;
281
282 protected:
Scope(ArenaAllocator *allocator, Scope *parent)283 explicit Scope(ArenaAllocator *allocator, Scope *parent)
284 : parent_(parent), decls_(allocator->Adapter()), bindings_(allocator->Adapter())
285 {
286 }
287
Scope(ArenaAllocator *allocator, Scope *parent, ScopeFlags flags)288 explicit Scope(ArenaAllocator *allocator, Scope *parent, ScopeFlags flags)
289 : parent_(parent), decls_(allocator->Adapter()), bindings_(allocator->Adapter()), flags_(flags)
290 {
291 }
292
293 /**
294 * @return true - if the variable is shadowed
295 * false - otherwise
296 */
297 using VariableVisitor = std::function<bool(const Variable *)>;
298
299 /**
300 * @return true - if the variable is shadowed
301 * false - otherwise
302 */
303 std::tuple<Scope *, bool> IterateShadowedVariables(const util::StringView &name, const VariableVisitor &visitor);
304
305 Variable *AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
306 [[maybe_unused]] ScriptExtension extension);
307
308 Variable *AddLocalVar(ArenaAllocator *allocator, Decl *newDecl);
309
310 private:
311 template <
312 typename ResultT, typename ScopeT,
313 std::enable_if_t<std::is_same_v<ResultT, ConstScopeFindResult> || std::is_same_v<ResultT, ScopeFindResult>,
314 bool> = true,
315 std::enable_if_t<std::is_pointer_v<ScopeT> && std::is_base_of_v<Scope, std::remove_pointer_t<ScopeT>>, bool> =
316 true>
FindImpl(ScopeT &&scope, const util::StringView &name, const ResolveBindingOptions options)317 static ResultT FindImpl(ScopeT &&scope, const util::StringView &name, const ResolveBindingOptions options)
318 {
319 uint32_t level = 0;
320 uint32_t lexLevel = 0;
321 // iter will be the EXACT type of scope with cv-qualifiers
322 auto &&iter = scope;
323
324 if (iter->IsFunctionParamScope()) {
325 auto *const v = iter->FindLocal(name, options);
326
327 if (v != nullptr) {
328 return {name, iter, level, lexLevel, v};
329 }
330
331 level++;
332 const auto *const funcVariableScope = iter->AsFunctionParamScope()->GetFunctionScope();
333
334 if (funcVariableScope != nullptr && funcVariableScope->NeedLexEnv()) {
335 lexLevel++;
336 }
337
338 iter = iter->Parent();
339 }
340
341 while (iter != nullptr) {
342 auto *const v = iter->FindLocal(name, options);
343
344 if (v != nullptr) {
345 return {name, iter, level, lexLevel, v};
346 }
347
348 if (iter->IsVariableScope()) {
349 level++;
350
351 if (iter->AsVariableScope()->NeedLexEnv()) {
352 lexLevel++;
353 }
354 }
355
356 iter = iter->Parent();
357 }
358
359 return {name, nullptr, 0, 0, nullptr};
360 }
361
362 Scope *parent_ {};
363 ArenaVector<Decl *> decls_;
364 VariableMap bindings_;
365 ir::AstNode *node_ {};
366 ScopeFlags flags_ {};
367 const compiler::IRNode *startIns_ {};
368 const compiler::IRNode *endIns_ {};
369 };
370
371 class VariableScope : public Scope {
372 public:
373 ~VariableScope() override = default;
374 NO_COPY_SEMANTIC(VariableScope);
375 NO_MOVE_SEMANTIC(VariableScope);
376
NextSlot()377 uint32_t NextSlot()
378 {
379 return slotIndex_++;
380 }
381
LexicalSlots() const382 uint32_t LexicalSlots() const
383 {
384 return slotIndex_;
385 }
386
NeedLexEnv() const387 bool NeedLexEnv() const
388 {
389 return slotIndex_ != 0;
390 }
391
EvalBindings() const392 uint32_t EvalBindings() const
393 {
394 return evalBindings_;
395 }
396
397 void CheckDirectEval(public_lib::Context *context);
398
399 protected:
VariableScope(ArenaAllocator *allocator, Scope *parent)400 explicit VariableScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent) {}
401
402 template <typename T>
403 Variable *AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
404
405 template <typename T>
406 Variable *AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
407 [[maybe_unused]] ScriptExtension extension);
408
409 template <typename T>
410 Variable *AddTSBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
411
412 template <typename T>
413 Variable *AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
414
415 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
416 uint32_t evalBindings_ {};
417 uint32_t slotIndex_ {};
418 // NOLINTEND(misc-non-private-member-variables-in-classes)
419 };
420
421 class ParamScope : public Scope {
422 public:
423 ScopeType Type() const override
424 {
425 return ScopeType::PARAM;
426 }
427
Params()428 ArenaVector<LocalVariable *> &Params()
429 {
430 return params_;
431 }
432
Params() const433 const ArenaVector<LocalVariable *> &Params() const
434 {
435 return params_;
436 }
437
438 std::tuple<ParameterDecl *, ir::AstNode *, Variable *> AddParamDecl(ArenaAllocator *allocator, ir::AstNode *param);
439
440 protected:
ParamScope(ArenaAllocator *allocator, Scope *parent)441 explicit ParamScope(ArenaAllocator *allocator, Scope *parent)
442 : Scope(allocator, parent), params_(allocator->Adapter())
443 {
444 }
445
446 Variable *AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
447
448 // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
449 ArenaVector<LocalVariable *> params_;
450 };
451
452 class FunctionScope;
453
454 class FunctionParamScope : public ParamScope {
455 public:
FunctionParamScope(ArenaAllocator *allocator, Scope *parent)456 explicit FunctionParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
457
GetFunctionScope() const458 FunctionScope *GetFunctionScope() const
459 {
460 return functionScope_;
461 }
462
BindFunctionScope(FunctionScope *funcScope)463 void BindFunctionScope(FunctionScope *funcScope)
464 {
465 functionScope_ = funcScope;
466 }
467
NameVar() const468 LocalVariable *NameVar() const
469 {
470 return nameVar_;
471 }
472
473 void BindName(ArenaAllocator *allocator, util::StringView name);
474
475 ScopeType Type() const override
476 {
477 return ScopeType::FUNCTION_PARAM;
478 }
479
480 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
481 [[maybe_unused]] ScriptExtension extension) override;
482
483 friend class FunctionScope;
484 template <typename E, typename T>
485 friend class ScopeWithParamScope;
486
487 private:
488 FunctionScope *functionScope_ {};
489 LocalVariable *nameVar_ {};
490 };
491
492 template <typename E, typename T>
493 class ScopeWithParamScope : public E {
494 public:
ScopeWithParamScope(ArenaAllocator *allocator, Scope *parent)495 explicit ScopeWithParamScope(ArenaAllocator *allocator, Scope *parent) : E(allocator, parent), paramScope_(nullptr)
496 {
497 }
498
BindParamScope(T *paramScope)499 void BindParamScope(T *paramScope)
500 {
501 AssignParamScope(paramScope);
502 this->MergeBindings(paramScope->Bindings());
503 }
504
AssignParamScope(T *paramScope)505 void AssignParamScope(T *paramScope)
506 {
507 ASSERT(this->Parent() == paramScope);
508 paramScope_ = paramScope;
509 }
510
ParamScope()511 T *ParamScope()
512 {
513 return paramScope_;
514 }
515
ParamScope() const516 const T *ParamScope() const
517 {
518 return paramScope_;
519 }
520
521 protected:
522 // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
523 T *paramScope_;
524 };
525
526 class LocalScope : public Scope {
527 public:
LocalScope(ArenaAllocator *allocator, Scope *parent)528 explicit LocalScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent) {}
LocalScope(ArenaAllocator *allocator, Scope *parent, ScopeFlags flags)529 explicit LocalScope(ArenaAllocator *allocator, Scope *parent, ScopeFlags flags) : Scope(allocator, parent, flags) {}
530
531 ScopeType Type() const override
532 {
533 return ScopeType::LOCAL;
534 }
535
536 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
537 [[maybe_unused]] ScriptExtension extension) override;
538 };
539
540 class LocalScopeWithTypeAlias : public LocalScope {
541 public:
LocalScopeWithTypeAlias(ArenaAllocator *allocator, Scope *parent)542 explicit LocalScopeWithTypeAlias(ArenaAllocator *allocator, Scope *parent)
543 : LocalScope(allocator, parent),
544 typeAliasScope_(allocator->New<LocalScope>(allocator, this, ScopeFlags::TYPE_ALIAS))
545 {
546 }
LocalScopeWithTypeAlias(ArenaAllocator *allocator, Scope *parent, ScopeFlags flags)547 explicit LocalScopeWithTypeAlias(ArenaAllocator *allocator, Scope *parent, ScopeFlags flags)
548 : LocalScope(allocator, parent, flags),
549 typeAliasScope_(allocator->New<LocalScope>(allocator, this, ScopeFlags::TYPE_ALIAS))
550 {
551 }
552
553 Variable *FindLocal(const util::StringView &name, ResolveBindingOptions options) const override;
554
555 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
556 [[maybe_unused]] ScriptExtension extension) override;
557
TypeAliasScope() const558 const LocalScope *TypeAliasScope() const
559 {
560 return typeAliasScope_;
561 }
562
TypeAliasScope()563 LocalScope *TypeAliasScope()
564 {
565 return typeAliasScope_;
566 }
567
568 private:
569 LocalScope *typeAliasScope_;
570 };
571
572 class FunctionScope : public ScopeWithParamScope<VariableScope, FunctionParamScope> {
573 public:
FunctionScope(ArenaAllocator *allocator, Scope *parent)574 explicit FunctionScope(ArenaAllocator *allocator, Scope *parent)
575 : ScopeWithParamScope(allocator, parent),
576 typeAliasScope_(allocator->New<LocalScope>(allocator, this, ScopeFlags::TYPE_ALIAS))
577 {
578 }
579
580 ScopeType Type() const override
581 {
582 return ScopeType::FUNCTION;
583 }
584
BindName(util::StringView name)585 void BindName(util::StringView name)
586 {
587 name_ = name;
588 }
589
BindInternalName(util::StringView internalName)590 void BindInternalName(util::StringView internalName)
591 {
592 internalName_ = internalName;
593 }
594
Name() const595 const util::StringView &Name() const
596 {
597 return name_;
598 }
599
InternalName() const600 const util::StringView &InternalName() const
601 {
602 return internalName_;
603 }
604
TypeAliasScope() const605 const LocalScope *TypeAliasScope() const
606 {
607 return typeAliasScope_;
608 }
609
610 Variable *FindLocal(const util::StringView &name, ResolveBindingOptions options) const override;
611
612 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
613 [[maybe_unused]] ScriptExtension extension) override;
614
615 private:
616 util::StringView name_ {};
617 util::StringView internalName_ {};
618 LocalScope *typeAliasScope_;
619 };
620
621 class ClassScope : public LocalScopeWithTypeAlias {
622 public:
ClassScope(ArenaAllocator *allocator, Scope *parent)623 explicit ClassScope(ArenaAllocator *allocator, Scope *parent)
624 : LocalScopeWithTypeAlias(allocator, parent),
625 staticDeclScope_(allocator->New<LocalScope>(allocator, this, ScopeFlags::STATIC_DECL_SCOPE)),
626 staticFieldScope_(allocator->New<LocalScope>(allocator, staticDeclScope_, ScopeFlags::STATIC_FIELD_SCOPE)),
627 staticMethodScope_(allocator->New<LocalScope>(allocator, staticFieldScope_, ScopeFlags::STATIC_METHOD_SCOPE)),
628 instanceDeclScope_(allocator->New<LocalScope>(allocator, staticMethodScope_, ScopeFlags::DECL_SCOPE)),
629 instanceFieldScope_(allocator->New<LocalScope>(allocator, instanceDeclScope_, ScopeFlags::FIELD_SCOPE)),
630 instanceMethodScope_(allocator->New<LocalScope>(allocator, instanceFieldScope_, ScopeFlags::METHOD_SCOPE))
631 {
632 }
633
634 ScopeType Type() const override
635 {
636 return ScopeType::CLASS;
637 }
638
StaticDeclScope()639 LocalScope *StaticDeclScope()
640 {
641 return staticDeclScope_;
642 }
643
StaticDeclScope() const644 const LocalScope *StaticDeclScope() const
645 {
646 return staticDeclScope_;
647 }
648
StaticFieldScope()649 LocalScope *StaticFieldScope()
650 {
651 return staticFieldScope_;
652 }
653
StaticFieldScope() const654 const LocalScope *StaticFieldScope() const
655 {
656 return staticFieldScope_;
657 }
658
StaticMethodScope()659 LocalScope *StaticMethodScope()
660 {
661 return staticMethodScope_;
662 }
663
StaticMethodScope() const664 const LocalScope *StaticMethodScope() const
665 {
666 return staticMethodScope_;
667 }
668
InstanceFieldScope()669 LocalScope *InstanceFieldScope()
670 {
671 return instanceFieldScope_;
672 }
673
InstanceFieldScope() const674 const LocalScope *InstanceFieldScope() const
675 {
676 return instanceFieldScope_;
677 }
678
InstanceMethodScope()679 LocalScope *InstanceMethodScope()
680 {
681 return instanceMethodScope_;
682 }
683
InstanceMethodScope() const684 const LocalScope *InstanceMethodScope() const
685 {
686 return instanceMethodScope_;
687 }
688
InstanceDeclScope()689 LocalScope *InstanceDeclScope()
690 {
691 return instanceDeclScope_;
692 }
693
InstanceDeclScope() const694 const LocalScope *InstanceDeclScope() const
695 {
696 return instanceDeclScope_;
697 }
698
GetAndIncrementAnonymousClassIdx() const699 uint32_t GetAndIncrementAnonymousClassIdx() const
700 {
701 return anonymousClassIdx_++;
702 }
703
704 Variable *FindLocal(const util::StringView &name, ResolveBindingOptions options) const override;
705
706 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
707 [[maybe_unused]] ScriptExtension extension) override;
708
709 class BindingProps {
710 public:
711 BindingProps() = default;
712
SetFlagsType(VariableFlags flagsType)713 void SetFlagsType(VariableFlags flagsType)
714 {
715 flags_ |= flagsType;
716 }
SetBindingProps(VariableFlags flags, ir::Identifier *ident, LocalScope *targetScope)717 void SetBindingProps(VariableFlags flags, ir::Identifier *ident, LocalScope *targetScope)
718 {
719 flags_ |= flags;
720 ident_ = ident;
721 targetScope_ = targetScope;
722 }
GetFlags() const723 VariableFlags GetFlags() const
724 {
725 return flags_;
726 }
GetIdent()727 ir::Identifier *GetIdent()
728 {
729 return ident_;
730 }
GetTargetScope()731 LocalScope *GetTargetScope()
732 {
733 return targetScope_;
734 }
735
736 private:
737 VariableFlags flags_ = VariableFlags::NONE;
738 ir::Identifier *ident_ {};
739 LocalScope *targetScope_ {};
740 };
741
742 void SetBindingProps(Decl *newDecl, BindingProps *props, bool isStatic);
743
744 private:
745 LocalScope *staticDeclScope_;
746 LocalScope *staticFieldScope_;
747 LocalScope *staticMethodScope_;
748 LocalScope *instanceDeclScope_;
749 LocalScope *instanceFieldScope_;
750 LocalScope *instanceMethodScope_;
751 mutable uint32_t anonymousClassIdx_ {1};
752 };
753
754 class CatchParamScope : public ParamScope {
755 public:
CatchParamScope(ArenaAllocator *allocator, Scope *parent)756 explicit CatchParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
757
758 ScopeType Type() const override
759 {
760 return ScopeType::CATCH_PARAM;
761 }
762
763 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
764 [[maybe_unused]] ScriptExtension extension) override;
765
766 friend class CatchScope;
767 };
768
769 class CatchScope : public ScopeWithParamScope<LocalScopeWithTypeAlias, CatchParamScope> {
770 public:
CatchScope(ArenaAllocator *allocator, Scope *parent)771 explicit CatchScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
772
773 ScopeType Type() const override
774 {
775 return ScopeType::CATCH;
776 }
777
778 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
779 [[maybe_unused]] ScriptExtension extension) override;
780 };
781
782 class LoopScope;
783
784 class LoopDeclarationScope : public VariableScope {
785 public:
LoopDeclarationScope(ArenaAllocator *allocator, Scope *parent)786 explicit LoopDeclarationScope(ArenaAllocator *allocator, Scope *parent) : VariableScope(allocator, parent) {}
787
788 ScopeType Type() const override
789 {
790 return loopType_;
791 }
792
793 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
794 [[maybe_unused]] ScriptExtension extension) override
795 {
796 return AddLocal(allocator, currentVariable, newDecl, extension);
797 }
798
InitScope()799 Scope *InitScope()
800 {
801 if (NeedLexEnv()) {
802 return initScope_;
803 }
804
805 return this;
806 }
807
808 void ConvertToVariableScope(ArenaAllocator *allocator);
809
810 private:
811 friend class LoopScope;
812 LoopScope *loopScope_ {};
813 LocalScope *initScope_ {};
814 ScopeType loopType_ {ScopeType::LOCAL};
815 };
816
817 class LoopScope : public VariableScope {
818 public:
LoopScope(ArenaAllocator *allocator, Scope *parent)819 explicit LoopScope(ArenaAllocator *allocator, Scope *parent) : VariableScope(allocator, parent)
820 {
821 // NOTE(kkonkuznetsov): currently LoopScope type has ScopeType::LOCAL
822 // therefore it does not respond to IsLoopScope() because it checks for type.
823 // This LOOP_SCOPE flag can be used to check that scope is actually a loop scope.
824 AddFlag(ScopeFlags::LOOP_SCOPE);
825 }
826
DeclScope()827 LoopDeclarationScope *DeclScope()
828 {
829 return declScope_;
830 }
831
BindDecls(LoopDeclarationScope *declScope)832 void BindDecls(LoopDeclarationScope *declScope)
833 {
834 declScope_ = declScope;
835 declScope_->loopScope_ = this;
836 }
837
838 ScopeType Type() const override
839 {
840 return loopType_;
841 }
842
843 void ConvertToVariableScope(ArenaAllocator *allocator);
844
845 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
846 [[maybe_unused]] ScriptExtension extension) override
847 {
848 return AddLocal(allocator, currentVariable, newDecl, extension);
849 }
850
851 protected:
852 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
853 LoopDeclarationScope *declScope_ {};
854 ScopeType loopType_ {ScopeType::LOCAL};
855 // NOLINTEND(misc-non-private-member-variables-in-classes)
856 };
857
858 class GlobalScope : public FunctionScope {
859 public:
GlobalScope(ArenaAllocator *allocator)860 explicit GlobalScope(ArenaAllocator *allocator)
861 : FunctionScope(allocator, nullptr), foreignBindings_(allocator->Adapter())
862 {
863 auto *paramScope = allocator->New<FunctionParamScope>(allocator, this);
864 paramScope_ = paramScope;
865 paramScope_->BindFunctionScope(this);
866 }
867
868 ScopeType Type() const override
869 {
870 return ScopeType::GLOBAL;
871 }
872
873 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
874 [[maybe_unused]] ScriptExtension extension) override;
875
876 InsertResult InsertBinding(const util::StringView &name, Variable *var) override;
877 InsertResult TryInsertBinding(const util::StringView &name, Variable *var) override;
878 void MergeBindings(VariableMap const &bindings) override;
879 VariableMap::size_type EraseBinding(const util::StringView &name) override;
880
881 InsertResult InsertForeignBinding(const util::StringView &name, Variable *var);
882 [[nodiscard]] bool IsForeignBinding(const util::StringView &name) const;
883
884 InsertResult InsertDynamicBinding(const util::StringView &name, Variable *var);
885
886 private:
887 InsertResult InsertImpl(const util::StringView &name, Variable *var, bool isForeign, bool isDynamic);
888
889 ArenaUnorderedMap<util::StringView, bool> foreignBindings_;
890 };
891
892 class ModuleScope : public GlobalScope {
893 public:
894 template <typename K, typename V>
895 using ModuleEntry = ArenaVector<std::pair<K, V>>;
896 using ImportDeclList = ArenaVector<ImportDecl *>;
897 using ExportDeclList = ArenaVector<ExportDecl *>;
898 using LocalExportNameMap = ArenaMultiMap<varbinder::Variable *, util::StringView>;
899
ModuleScope(ArenaAllocator *allocator)900 explicit ModuleScope(ArenaAllocator *allocator)
901 : GlobalScope(allocator),
902 allocator_(allocator),
903 imports_(allocator_->Adapter()),
904 exports_(allocator_->Adapter()),
905 localExports_(allocator_->Adapter())
906 {
907 }
908
909 ScopeType Type() const override
910 {
911 return ScopeType::MODULE;
912 }
913
Imports() const914 const ModuleEntry<ir::ImportDeclaration *, ImportDeclList> &Imports() const
915 {
916 return imports_;
917 }
918
Exports() const919 const ModuleEntry<ir::AstNode *, ExportDeclList> &Exports() const
920 {
921 return exports_;
922 }
923
LocalExports() const924 const LocalExportNameMap &LocalExports() const
925 {
926 return localExports_;
927 }
928
929 void AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls);
930
931 void AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl);
932
933 void AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls);
934
935 Variable *AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
936 [[maybe_unused]] ScriptExtension extension) override;
937
938 bool ExportAnalysis();
939
940 private:
941 Variable *AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
942
943 ArenaAllocator *allocator_;
944 ModuleEntry<ir::ImportDeclaration *, ImportDeclList> imports_;
945 ModuleEntry<ir::AstNode *, ExportDeclList> exports_;
946 LocalExportNameMap localExports_;
947 };
948
949 template <typename T>
AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)950 Variable *VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
951 {
952 if (!currentVariable) {
953 return InsertBinding(newDecl->Name(), allocator->New<T>(newDecl, VariableFlags::HOIST_VAR)).first->second;
954 }
955
956 switch (currentVariable->Declaration()->Type()) {
957 case DeclType::VAR: {
958 currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR);
959 [[fallthrough]];
960 }
961 case DeclType::PARAM:
962 case DeclType::FUNC: {
963 return currentVariable;
964 }
965 default: {
966 return nullptr;
967 }
968 }
969 }
970
971 template <typename T>
AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension)972 Variable *VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
973 [[maybe_unused]] ScriptExtension extension)
974 {
975 VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST;
976
977 if (!currentVariable) {
978 return InsertBinding(newDecl->Name(), allocator->New<T>(newDecl, flags)).first->second;
979 }
980
981 if (extension != ScriptExtension::JS || IsModuleScope()) {
982 return nullptr;
983 }
984
985 switch (currentVariable->Declaration()->Type()) {
986 case DeclType::VAR:
987 case DeclType::FUNC: {
988 currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR);
989 return currentVariable;
990 }
991 default: {
992 return nullptr;
993 }
994 }
995 }
996
997 template <typename T>
AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl, VariableFlags flags)998 Variable *VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable,
999 Decl *newDecl, VariableFlags flags)
1000 {
1001 ASSERT(!currentVariable);
1002 return InsertBinding(newDecl->Name(), allocator->New<T>(newDecl, flags)).first->second;
1003 }
1004
1005 template <typename T>
AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)1006 Variable *VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
1007 {
1008 if (currentVariable) {
1009 return nullptr;
1010 }
1011
1012 return InsertBinding(newDecl->Name(), allocator->New<T>(newDecl, VariableFlags::NONE)).first->second;
1013 }
1014
1015 template <typename T, typename... Args>
NewDecl(ArenaAllocator *allocator, Args &&...args)1016 T *Scope::NewDecl(ArenaAllocator *allocator, Args &&...args)
1017 {
1018 T *decl = allocator->New<T>(std::forward<Args>(args)...);
1019 decls_.push_back(decl);
1020
1021 return decl;
1022 }
1023
1024 template <typename DeclType, typename VariableType>
AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags)1025 VariableType *Scope::AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags)
1026 {
1027 if (FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS)) {
1028 return nullptr;
1029 }
1030
1031 auto *decl = allocator->New<DeclType>(name);
1032 auto *variable = allocator->New<VariableType>(decl, flags);
1033
1034 decls_.push_back(decl);
1035 bindings_.insert({decl->Name(), variable});
1036 variable->SetScope(this);
1037
1038 return variable;
1039 }
1040
1041 template <typename DeclType, typename VariableType>
CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, ir::AstNode *node)1042 VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, ir::AstNode *node)
1043 {
1044 auto *decl = allocator->New<DeclType>(name);
1045 auto *variable = allocator->New<VariableType>(decl, flags);
1046 decl->BindNode(node);
1047 return variable;
1048 }
1049
1050 template <typename T, typename... Args>
PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args)1051 Variable *Scope::PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args)
1052 {
1053 auto res = bindings_.find(name);
1054 if (res == bindings_.end()) {
1055 return bindings_.insert({name, allocator->New<T>(std::forward<Args>(args)...)}).first->second;
1056 }
1057
1058 res->second->Reset(std::forward<Args>(args)...);
1059 return res->second;
1060 }
1061 } // namespace ark::es2panda::varbinder
1062
1063 #endif
1064