• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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_VARBINDER_VARBINDER_H
17 #define ES2PANDA_VARBINDER_VARBINDER_H
18 
19 #include "lexer/token/sourceLocation.h"
20 #include "varbinder/scope.h"
21 
22 namespace ark::es2panda::parser {
23 class Program;
24 enum class ScriptKind;
25 }  // namespace ark::es2panda::parser
26 
27 namespace ark::es2panda::ir {
28 class AstNode;
29 class BlockStatement;
30 class CatchClause;
31 class ClassDefinition;
32 class Expression;
33 class ForUpdateStatement;
34 class Identifier;
35 class ScriptFunction;
36 class Statement;
37 class VariableDeclarator;
38 class TSFunctionType;
39 class ThisExpression;
40 class MemberExpression;
41 class ClassStaticBlock;
42 class Identifier;
43 class TSTypeAliasDeclaration;
44 class ClassProperty;
45 }  // namespace ark::es2panda::ir
46 
47 namespace ark::es2panda::public_lib {
48 struct Context;
49 }  // namespace ark::es2panda::public_lib
50 
51 namespace ark::es2panda::varbinder {
52 class ETSBinder;
53 
54 class VarBinder {
55 public:
VarBinder(ArenaAllocator * allocator)56     explicit VarBinder(ArenaAllocator *allocator) : allocator_(allocator), functionScopes_(allocator_->Adapter()) {}
57 
58     VarBinder() = delete;
59     NO_COPY_SEMANTIC(VarBinder);
60     NO_MOVE_SEMANTIC(VarBinder);
61     virtual ~VarBinder() = default;
62 
63     void InitTopScope();
64     virtual void IdentifierAnalysis();
65 
66     template <typename T, typename... Args>
67     T *AddDecl(const lexer::SourcePosition &pos, Args &&...args);
68 
69     template <typename T, typename... Args>
70     T *AddTsDecl(const lexer::SourcePosition &pos, Args &&...args);
71 
72     template <typename T, typename... Args>
73     std::tuple<T *, varbinder::Variable *> NewVarDecl(const lexer::SourcePosition &pos, Args &&...args);
74 
75     Variable *AddParamDecl(ir::Expression *param);
76 
SetProgram(parser::Program * program)77     void SetProgram(parser::Program *program) noexcept
78     {
79         program_ = program;
80     }
81 
Program()82     [[nodiscard]] parser::Program *Program() noexcept
83     {
84         return program_;
85     }
86 
Program()87     [[nodiscard]] const parser::Program *Program() const
88     {
89         ES2PANDA_ASSERT(program_);
90         return program_;
91     }
92 
SetContext(public_lib::Context * context)93     void SetContext(public_lib::Context *context)
94     {
95         context_ = context;
96     }
97 
GetContext()98     [[nodiscard]] public_lib::Context *GetContext() const
99     {
100         ES2PANDA_ASSERT(context_);
101         return context_;
102     }
103 
SetGenStdLib(bool genStdLib)104     void SetGenStdLib(bool genStdLib) noexcept
105     {
106         genStdLib_ = genStdLib;
107     }
108 
IsGenStdLib()109     [[nodiscard]] bool IsGenStdLib() noexcept
110     {
111         return genStdLib_;
112     }
113 
GetScope()114     [[nodiscard]] Scope *GetScope() const noexcept
115     {
116         return scope_;
117     }
118 
ResetAllScopes(GlobalScope * topScope,VariableScope * varScope,Scope * scope)119     void ResetAllScopes(GlobalScope *topScope, VariableScope *varScope, Scope *scope) noexcept
120     {
121         topScope_ = topScope;
122         varScope_ = varScope;
123         scope_ = scope;
124     }
125 
ResetTopScope(GlobalScope * topScope)126     void ResetTopScope(GlobalScope *topScope)
127     {
128         ES2PANDA_ASSERT(topScope_ == scope_);
129         topScope_ = topScope;
130         varScope_ = topScope_;
131         scope_ = topScope_;
132     }
133 
TopScope()134     [[nodiscard]] GlobalScope *TopScope() const noexcept
135     {
136         return topScope_;
137     }
138 
VarScope()139     [[nodiscard]] VariableScope *VarScope() const noexcept
140     {
141         return varScope_;
142     }
143 
IsETSBinder()144     [[nodiscard]] bool IsETSBinder() const noexcept
145     {
146         return Extension() == ScriptExtension::ETS;
147     }
148 
AsETSBinder()149     [[nodiscard]] const ETSBinder *AsETSBinder() const
150     {
151         ES2PANDA_ASSERT(Extension() == ScriptExtension::ETS);
152         return reinterpret_cast<const ETSBinder *>(this);
153     }
154 
AsETSBinder()155     [[nodiscard]] ETSBinder *AsETSBinder()
156     {
157         ES2PANDA_ASSERT(Extension() == ScriptExtension::ETS);
158         return reinterpret_cast<ETSBinder *>(this);
159     }
160 
161     void ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const;
162     void ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name, DeclType declType) const;
163     void ThrowLocalRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) const;
164     void ThrowUnresolvableType(const lexer::SourcePosition &pos, const util::StringView &name) const;
165     void ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const;
166     void ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const;
ThrowError(const lexer::SourcePosition & pos,const diagnostic::DiagnosticKind & kind)167     void ThrowError(const lexer::SourcePosition &pos, const diagnostic::DiagnosticKind &kind) const
168     {
169         ThrowError(pos, kind, util::DiagnosticMessageParams {});
170     }
171     virtual void ThrowError(const lexer::SourcePosition &pos, const diagnostic::DiagnosticKind &kind,
172                             const util::DiagnosticMessageParams &params) const;
173     virtual bool IsGlobalIdentifier(const util::StringView &str) const;
174 
175     void PropagateDirectEval() const;
176 
177     template <typename T>
178     friend class LexicalScope;
179 
Allocator()180     [[nodiscard]] ArenaAllocator *Allocator() const noexcept
181     {
182         return allocator_;
183     }
184 
Functions()185     [[nodiscard]] const ArenaVector<FunctionScope *> &Functions() const noexcept
186     {
187         return functionScopes_;
188     }
189 
Functions()190     [[nodiscard]] ArenaVector<FunctionScope *> &Functions() noexcept
191     {
192         return functionScopes_;
193     }
194 
Extension()195     [[nodiscard]] virtual ScriptExtension Extension() const noexcept
196     {
197         return ScriptExtension::JS;
198     }
199 
BindingOptions()200     [[nodiscard]] virtual ResolveBindingOptions BindingOptions() const noexcept
201     {
202         return ResolveBindingOptions::BINDINGS;
203     }
204 
205     LocalVariable *AddMandatoryParam(const std::string_view &name);
206 
207     inline static constexpr std::string_view const FUNCTION_ARGUMENTS = "arguments";
208     inline static constexpr std::string_view const MANDATORY_PARAM_FUNC = "=f";
209     inline static constexpr std::string_view const MANDATORY_PARAM_NEW_TARGET = "=nt";
210     inline static constexpr std::string_view const MANDATORY_PARAM_THIS = "=t";
211 
212     inline static constexpr std::uint32_t const MANDATORY_PARAM_FUNC_REG = 0U;
213     inline static constexpr std::uint32_t const MANDATORY_PARAMS_NUMBER = 3U;
214 
215     inline static constexpr std::string_view const LEXICAL_MANDATORY_PARAM_FUNC = "!f";
216     inline static constexpr std::string_view const LEXICAL_MANDATORY_PARAM_NEW_TARGET = "!nt";
217     inline static constexpr std::string_view const LEXICAL_MANDATORY_PARAM_THIS = "!t";
218 
219     inline static constexpr std::string_view const LEXICAL_CONTEXT_PARAM = "=eval";
220     inline static constexpr std::string_view const MAIN = "main";
221     inline static constexpr std::uint32_t const LEXICAL_CONTEXT_PARAM_REG = MANDATORY_PARAMS_NUMBER;
222     inline static constexpr std::string_view const STAR_IMPORT = "*";
223 
224     void ResolveReferenceDoWhileHelper(ir::AstNode *childNode);
225     void ResolveReferenceWhileHelper(ir::AstNode *childNode);
226     void ResolveReference(ir::AstNode *childNode);
227 
228 protected:
229     template <size_t N>
230     using MandatoryParams = std::array<std::string_view, N>;
231 
232     static constexpr MandatoryParams<MANDATORY_PARAMS_NUMBER> FUNCTION_MANDATORY_PARAMS = {
233         MANDATORY_PARAM_FUNC, MANDATORY_PARAM_NEW_TARGET, MANDATORY_PARAM_THIS};
234 
235     static constexpr MandatoryParams<MANDATORY_PARAMS_NUMBER + 1> EVAL_SCRIPT_MANDATORY_PARAMS = {
236         MANDATORY_PARAM_FUNC, MANDATORY_PARAM_NEW_TARGET, MANDATORY_PARAM_THIS, LEXICAL_CONTEXT_PARAM};
237 
238     static constexpr MandatoryParams<MANDATORY_PARAMS_NUMBER> ARROW_MANDATORY_PARAMS = {
239         MANDATORY_PARAM_FUNC, LEXICAL_MANDATORY_PARAM_NEW_TARGET, LEXICAL_MANDATORY_PARAM_THIS};
240 
241     static constexpr MandatoryParams<MANDATORY_PARAMS_NUMBER> CTOR_ARROW_MANDATORY_PARAMS = {
242         LEXICAL_MANDATORY_PARAM_FUNC, LEXICAL_MANDATORY_PARAM_NEW_TARGET, LEXICAL_MANDATORY_PARAM_THIS};
243 
244     void LookUpMandatoryReferences(const FunctionScope *funcScope, bool needLexicalFuncObj);
245     template <size_t N>
246     void AddMandatoryParams(const MandatoryParams<N> &params);
247     void AddMandatoryParams();
248     void LookupReference(const util::StringView &name);
249     void InstantiateArguments();
250     [[nodiscard]] bool InstantiateArgumentsImpl(Scope **scope, Scope *iter, const ir::AstNode *node);
251     void InstantiatePrivateContext(const ir::Identifier *ident) const;
252     void BuildVarDeclarator(ir::VariableDeclarator *varDecl);
253     void BuildVarDeclaratorId(ir::AstNode *childNode);
254     void BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt);
255     void BuildForInOfLoop(varbinder::LoopScope *loopScope, ir::AstNode *left, ir::Expression *right,
256                           ir::Statement *body);
257     void BuildCatchClause(ir::CatchClause *catchClauseStmt);
258     void BuildTypeAliasDeclaration(ir::TSTypeAliasDeclaration *const typeAliasDecl);
259     void ResolveReferences(const ir::AstNode *parent);
260     void VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction *func);
261     void VisitScriptFunction(ir::ScriptFunction *func);
262     [[nodiscard]] util::StringView BuildFunctionName(util::StringView name, uint32_t idx);
263 
264     void AddCompilableFunctionScope(varbinder::FunctionScope *funcScope);
265 
266     void InitializeClassBinding(ir::ClassDefinition *classDef);
267     void InitializeClassIdent(ir::ClassDefinition *classDef);
268 
269     virtual void LookupIdentReference(ir::Identifier *ident);
HandleCustomNodes(ir::AstNode * childNode)270     virtual void HandleCustomNodes(ir::AstNode *childNode)
271     {
272         ResolveReferences(childNode);
273     }
BuildSignatureDeclarationBaseParams(ir::AstNode * typeNode)274     virtual void BuildSignatureDeclarationBaseParams([[maybe_unused]] ir::AstNode *typeNode) {};
275     virtual void BuildClassDefinition(ir::ClassDefinition *classDef);
276     virtual void BuildClassProperty(const ir::ClassProperty *prop);
277     [[nodiscard]] virtual bool BuildInternalName(ir::ScriptFunction *scriptFunc);
278     virtual void AddCompilableFunction(ir::ScriptFunction *func);
279 
CleanUp()280     virtual void CleanUp()
281     {
282         topScope_ = nullptr;
283         scope_ = nullptr;
284         varScope_ = nullptr;
285         functionScopes_.clear();
286     }
287 
288 private:
289     parser::Program *program_ {};
290     ArenaAllocator *allocator_ {};
291     public_lib::Context *context_ {};
292     GlobalScope *topScope_ {};
293     Scope *scope_ {};
294     VariableScope *varScope_ {};
295     ArenaVector<FunctionScope *> functionScopes_;
296     ResolveBindingOptions bindingOptions_ {};
297     bool genStdLib_ {false};
298 };
299 
300 template <typename T>
301 class LexicalScope {
302 public:
303     template <typename... Args>
LexicalScope(VarBinder * varbinder,Args &&...args)304     explicit LexicalScope(VarBinder *varbinder, Args &&...args)
305         : LexicalScope(
306               varbinder->Allocator()->New<T>(varbinder->Allocator(), varbinder->scope_, std::forward<Args>(args)...),
307               varbinder)
308     {
309     }
310 
GetScope()311     T *GetScope() const
312     {
313         return scope_;
314     }
315 
~LexicalScope()316     ~LexicalScope()
317     {
318         ES2PANDA_ASSERT(varbinder_);
319         varbinder_->scope_ = prevScope_;
320         varbinder_->varScope_ = prevVarScope_;
321     }
322 
323     [[nodiscard]] static LexicalScope<T> Enter(VarBinder *varbinder, T *scope, bool checkEval = true)
324     {
325         LexicalScope<T> lexScope(scope, varbinder);
326         if (!checkEval || varbinder->Extension() == ScriptExtension::TS) {
327             return lexScope;
328         }
329 
330         // NOLINTNEXTLINE(readability-braces-around-statements)
331         if constexpr (std::is_same_v<T, FunctionParamScope>) {
332             varbinder->varScope_ = scope->GetFunctionScope();
333             varbinder->varScope_->CheckDirectEval(varbinder->context_);
334             // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation)
335         } else if constexpr (std::is_same_v<T, FunctionScope>) {
336             varbinder->varScope_ = scope;
337             varbinder->varScope_->CheckDirectEval(varbinder->context_);
338             // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation)
339         } else if constexpr (std::is_same_v<T, LoopScope>) {
340             if (scope->IsLoopScope()) {
341                 varbinder->varScope_ = scope;
342                 varbinder->varScope_->CheckDirectEval(varbinder->context_);
343             }
344             // NOLINTNEXTLINE(readability-braces-around-statements,readability-misleading-indentation)
345         } else if constexpr (std::is_same_v<T, LoopDeclarationScope>) {
346             if (scope->IsLoopDeclarationScope()) {
347                 varbinder->varScope_ = scope;
348                 varbinder->varScope_->CheckDirectEval(varbinder->context_);
349             }
350         }
351 
352         return lexScope;
353     }
354 
355     DEFAULT_MOVE_SEMANTIC(LexicalScope);
356 
357 private:
358     NO_COPY_SEMANTIC(LexicalScope);
359 
LexicalScope(T * scope,VarBinder * varbinder)360     explicit LexicalScope(T *scope, VarBinder *varbinder)
361         : varbinder_(varbinder), scope_(scope), prevScope_(varbinder->scope_), prevVarScope_(varbinder->varScope_)
362     {
363         varbinder_->scope_ = scope_;
364     }
365 
366     VarBinder *varbinder_ {};
367     T *scope_ {};
368     Scope *prevScope_ {};
369     VariableScope *prevVarScope_ {};
370 };
371 
372 template <size_t N>
AddMandatoryParams(const MandatoryParams<N> & params)373 void VarBinder::AddMandatoryParams(const MandatoryParams<N> &params)
374 {
375     ES2PANDA_ASSERT(scope_->IsFunctionVariableScope());
376 
377     auto scopeCtx = LexicalScope<FunctionParamScope>::Enter(this, scope_->AsFunctionVariableScope()->ParamScope());
378 
379     for (auto iter = params.rbegin(); iter != params.rend(); ++iter) {
380         AddMandatoryParam(*iter);
381     }
382 }
383 
384 template <typename T, typename... Args>
AddTsDecl(const lexer::SourcePosition & pos,Args &&...args)385 T *VarBinder::AddTsDecl(const lexer::SourcePosition &pos, Args &&...args)
386 {
387     T *decl = Allocator()->New<T>(std::forward<Args>(args)...);
388 
389     if (scope_->AddTsDecl(Allocator(), decl, Extension()) == nullptr) {
390         ThrowRedeclaration(pos, decl->Name(), decl->Type());
391     }
392 
393     return decl;
394 }
395 
396 template <typename T, typename... Args>
AddDecl(const lexer::SourcePosition & pos,Args &&...args)397 T *VarBinder::AddDecl(const lexer::SourcePosition &pos, Args &&...args)
398 {
399     T *decl = Allocator()->New<T>(std::forward<Args>(args)...);
400 
401     if (scope_->AddDecl(Allocator(), decl, Extension()) == nullptr) {
402         ThrowRedeclaration(pos, decl->Name(), decl->Type());
403     }
404 
405     return decl;
406 }
407 
408 template <typename T, typename... Args>
NewVarDecl(const lexer::SourcePosition & pos,Args &&...args)409 std::tuple<T *, varbinder::Variable *> VarBinder::NewVarDecl(const lexer::SourcePosition &pos, Args &&...args)
410 {
411     T *decl = Allocator()->New<T>(std::forward<Args>(args)...);
412     auto *allocator = Allocator();
413     auto extension = Extension();
414     varbinder::Variable *var = scope_->AddDecl(allocator, decl, extension);
415 
416     if (var == nullptr) {
417         ThrowRedeclaration(pos, decl->Name(), decl->Type());
418         var = scope_->FindLocal(decl->Name(), ResolveBindingOptions::BINDINGS);
419     }
420 
421     ES2PANDA_ASSERT(var != nullptr);
422     return {decl, var};
423 }
424 }  // namespace ark::es2panda::varbinder
425 #endif
426