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