1/*
2 * Copyright (c) 2023-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_CORE_SCOPES_INIT_PHASE_H
17#define ES2PANDA_COMPILER_CORE_SCOPES_INIT_PHASE_H
18
19#include "compiler/lowering/phase.h"
20#include "util/helpers.h"
21#include "parser/parserFlags.h"
22#include "varbinder/tsBinding.h"
23#include "varbinder/ETSBinder.h"
24#include "compiler/lowering/scopesInit/savedBindingsCtx.h"
25#include "checker/checker.h"
26#include "ir/visitor/IterateAstVisitor.h"
27#include "ir/expressions/literals/undefinedLiteral.h"
28#include "ir/expressions/blockExpression.h"
29#include "ir/ets/etsUnionType.h"
30#include "ir/ets/etsTuple.h"
31
32namespace ark::es2panda::compiler {
33
34/**
35 * Responsible for initialization of scopes. Should be called right after Parser stage.
36 */
37// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
38class ScopesInitPhase : public Phase, public ir::visitor::IterateAstVisitor {
39public:
40    using PhaseContext = public_lib::Context;
41
42    static constexpr std::string_view NAME = "ScopesInitPhase";
43
44    std::string_view Name() const override
45    {
46        return NAME;
47    }
48
49    bool Perform(PhaseContext *ctx, parser::Program *program) override;
50
51protected:
52    void SetProgram(parser::Program *program) noexcept;
53
54    void Prepare(PhaseContext *ctx, parser::Program *program);
55
56    /**
57     * Should be called at the end of each program perform
58     */
59    void Finalize();
60
61    /**
62     * Check if there's only one default export and no named export redeclaration,
63     * throw error if so.
64     * Side effect: fill local_exports_
65     */
66    void AnalyzeExports();
67
68protected:
69    template <typename T>
70    void CallNode(T *node)
71    {
72        if (node) {
73            node->Accept(this);
74        }
75    }
76
77    template <typename T>
78    void CallNode(const ArenaVector<T *> &nodes)
79    {
80        for (auto *node : nodes) {
81            CallNode(node);
82        }
83    }
84
85    void CallFuncParams(const ArenaVector<ir::Expression *> &params);
86    void IterateNoTParams(ir::ClassDefinition *classDef);
87
88protected:
89    void ThrowSyntaxError(std::string_view errorMessage, const lexer::SourcePosition &pos) const;
90
91    void VisitFunctionExpression(ir::FunctionExpression *funcExpr) override;
92    void VisitScriptFunction(ir::ScriptFunction *scriptFunction) override;
93    void VisitBlockStatement(ir::BlockStatement *blockStmt) override;
94    void VisitImportDeclaration(ir::ImportDeclaration *importDeclaration) override;
95    void VisitClassStaticBlock(ir::ClassStaticBlock *staticBlock) override;
96    void VisitClassDefinition(ir::ClassDefinition *classDef) override;
97    void VisitMethodDefinition(ir::MethodDefinition *methodDefinition) override;
98    void VisitForUpdateStatement(ir::ForUpdateStatement *forUpdateStmt) override;
99    void VisitForInStatement(ir::ForInStatement *forInStmt) override;
100    void VisitForOfStatement(ir::ForOfStatement *forOfStmt) override;
101    void VisitCatchClause(ir::CatchClause *catchClause) override;
102    void VisitVariableDeclarator(ir::VariableDeclarator *varDecl) override;
103    void VisitSwitchStatement(ir::SwitchStatement *switchStmt) override;
104    void VisitWhileStatement(ir::WhileStatement *whileStmt) override;
105    void VisitETSStructDeclaration(ir::ETSStructDeclaration *structDecl) override;
106    void VisitClassDeclaration(ir::ClassDeclaration *classDecl) override;
107    void VisitDoWhileStatement(ir::DoWhileStatement *doWhileStmt) override;
108    void VisitFunctionDeclaration(ir::FunctionDeclaration *funcDecl) override;
109    void VisitExportAllDeclaration(ir::ExportAllDeclaration *exportAllDecl) override;
110    void VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecifier *importSpec) override;
111    void VisitImportSpecifier(ir::ImportSpecifier *importSpec) override;
112    void VisitImportDefaultSpecifier(ir::ImportDefaultSpecifier *importSpec) override;
113    void VisitExportDefaultDeclaration(ir::ExportDefaultDeclaration *exportDecl) override;
114    void VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl) override;
115    void VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowExpr) override;
116    void VisitDirectEvalExpression(ir::DirectEvalExpression *directCallExpr) override;
117    void VisitTSFunctionType(ir::TSFunctionType *funcType) override;
118
119protected:
120    varbinder::Scope *GetScope()
121    {
122        return VarBinder()->GetScope();
123    }
124
125    ArenaAllocator *Allocator()
126    {
127        return program_->Allocator();
128    }
129
130    parser::Program *Program()
131    {
132        return program_;
133    }
134
135    const parser::Program *Program() const
136    {
137        return program_;
138    }
139
140    PhaseContext *Context()
141    {
142        return ctx_;
143    }
144
145    [[nodiscard]] varbinder::VarBinder *VarBinder() const
146    {
147        return program_->VarBinder();
148    }
149
150protected:
151    virtual void CreateFuncDecl(ir::ScriptFunction *func);
152    virtual util::StringView FormInterfaceOrEnumDeclarationIdBinding(ir::Identifier *id);
153    void HandleFunction(ir::ScriptFunction *function);
154    varbinder::FunctionParamScope *HandleFunctionSig(ir::TSTypeParameterDeclaration *typeParams,
155                                                     const ir::FunctionSignature::FunctionParams &params,
156                                                     ir::TypeNode *returnType);
157
158    /**
159     * Handle block from existing scope
160     */
161    void HandleBlockStmt(ir::BlockStatement *block, varbinder::Scope *scope);
162
163    template <typename ForT>
164    void HandleFor(varbinder::LoopDeclarationScope *declScope, varbinder::LoopScope *loopScope, ForT *forStmt)
165    {
166        loopScope->BindDecls(declScope);
167        BindScopeNode(loopScope, forStmt);
168        loopScope->DeclScope()->BindNode(forStmt);
169    }
170
171protected:
172    virtual varbinder::Decl *BindClassName(ir::ClassDefinition *classDef);
173
174    template <class Scope, class Node>
175    static void BindScopeNode(Scope *scope, Node *node)
176    {
177        if (node->Scope() == nullptr || node->IsBlockStatement()) {
178            scope->BindNode(node);
179            node->SetScope(scope);
180        }
181    }
182
183    static void BindFunctionScopes(varbinder::FunctionScope *scope, varbinder::FunctionParamScope *paramScope);
184
185    void BindClassDefinition(ir::ClassDefinition *classDef);
186
187    std::tuple<varbinder::Decl *, varbinder::Variable *> AddOrGetVarDecl(ir::VariableDeclaratorFlag flag,
188                                                                         lexer::SourcePosition startLoc,
189                                                                         const ir::Identifier *id);
190
191    virtual void BindVarDecl([[maybe_unused]] ir::Identifier *binding, ir::Expression *init, varbinder::Decl *decl,
192                             [[maybe_unused]] varbinder::Variable *var);
193    virtual void AttachLabelToScope(ir::AstNode *node);
194
195private:
196    PhaseContext *ctx_ {};
197    parser::Program *program_ {};
198};
199
200/**
201 * Specialization for typed script languages (typescript, ets)
202 */
203class ScopeInitTyped : public ScopesInitPhase {
204protected:
205public:
206    void VisitTSModuleDeclaration(ir::TSModuleDeclaration *moduleDecl) override;
207
208    void VisitTSModuleBlock(ir::TSModuleBlock *block) override;
209
210    void VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration *typeAliasDecl) override;
211
212    util::StringView FormInterfaceOrEnumDeclarationIdBinding(ir::Identifier *id) override;
213
214    virtual bool AllowInterfaceRedeclaration()
215    {
216        return false;
217    }
218
219    void VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration *interfDecl) override;
220
221    void VisitTSEnumMember(ir::TSEnumMember *enumMember) override;
222
223    void VisitTSEnumDeclaration(ir::TSEnumDeclaration *enumDecl) override;
224
225    void VisitTSTypeParameter(ir::TSTypeParameter *typeParam) override;
226
227    void VisitTSTypeParameterDeclaration(ir::TSTypeParameterDeclaration *paramDecl) override;
228
229    void VisitClassDefinition(ir::ClassDefinition *classDef) override;
230};
231
232class InitScopesPhaseJs : public ScopesInitPhase {
233public:
234    InitScopesPhaseJs() = default;
235    NO_COPY_SEMANTIC(InitScopesPhaseJs);
236    NO_MOVE_SEMANTIC(InitScopesPhaseJs);
237
238    ~InitScopesPhaseJs() override = default;
239};
240
241class InitScopesPhaseTs : public ScopeInitTyped {
242protected:
243    bool AllowInterfaceRedeclaration() override
244    {
245        return true;
246    }
247
248    void VisitTSMappedType([[maybe_unused]] ir::TSMappedType *mapped) override {}
249    void VisitTSInferType([[maybe_unused]] ir::TSInferType *infer) override {}
250    void VisitExportDefaultDeclaration(ir::ExportDefaultDeclaration *exportDecl) override;
251    void VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl) override;
252    void VisitImportDeclaration(ir::ImportDeclaration *importDeclaration) override;
253    void VisitTSFunctionType(ir::TSFunctionType *constrType) override;
254    void VisitTSConstructorType(ir::TSConstructorType *constrT) override;
255    void VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowFExpr) override;
256    void VisitTSSignatureDeclaration(ir::TSSignatureDeclaration *signDecl) override;
257    void VisitTSMethodSignature(ir::TSMethodSignature *methodSign) override;
258
259    void CreateFuncDecl(ir::ScriptFunction *func) override;
260};
261
262class InitScopesPhaseETS : public ScopeInitTyped {
263public:
264    InitScopesPhaseETS() = default;
265    NO_COPY_SEMANTIC(InitScopesPhaseETS);
266    NO_MOVE_SEMANTIC(InitScopesPhaseETS);
267
268    /**
269     * Set scopes for ast-subtree
270     * @param node ast-subtree, for this node and all children scopes will be initialized.
271     * @param varbinder ref to VarBinder. All varbinder scopes should be set to current context.
272     * Note: It's programmer responsibility to prepare VarBinder (remove previous names, set current scope, etc...)
273     *
274     * Example:
275     * f<T>(x: Int) :  {
276     *     let y = 0;
277     * }
278     * After ScopesInitPhase scope structure will look something like this:
279     * global_scope:
280     *     [f],
281     *     local_scope:
282     *        [T],
283     *        function_param_scope:
284     *            [x],
285     *            function_scope:
286     *                [y]
287     * Suppose you want to rewrite function body in some lowering later to
288     * {
289     *     let z = 123;
290     * }
291     *
292     * Then you should pass your new created node = ir::BlockStatement() to RunExternalNode,
293     * set varbinder to previous `function_scope` and call RunExternalNode(node, varbinder).
294     * It will update scopes to:
295     * global_scope:
296     *     [f],
297     *     local_scope:
298     *        [T],
299     *        function_param_scope:
300     *            [x],
301     *            function_scope:
302     *                [z]
303     */
304    static void RunExternalNode(ir::AstNode *node, varbinder::VarBinder *varbinder);
305    /**
306     * Same as previous, just uses varbinder from ctx->VarBinder()
307     */
308    static void RunExternalNode(ir::AstNode *node, parser::Program *ctx);
309
310    /**
311     * Run scope initialization on program.
312     * It's not same as RunExternalNode(program->Ast()), because there's some specific handling for top scope.
313     * @param ctx
314     * @param program - program you want to set scopes on.
315     * @return true if successful.
316     */
317    bool Perform(PhaseContext *ctx, parser::Program *program) override;
318
319    ~InitScopesPhaseETS() override = default;
320
321private:
322    void HandleProgram(parser::Program *program);
323
324    void HandleETSScript(ir::BlockStatement *script);
325
326    void ParseGlobalClass(ir::ClassDefinition *global);
327
328    void AddGlobalDeclaration(ir::AstNode *node);
329
330    varbinder::Decl *BindClassName([[maybe_unused]] ir::ClassDefinition *identNode) override
331    {
332        return nullptr;
333    }
334
335    void BindVarDecl(ir::Identifier *binding, ir::Expression *init, varbinder::Decl *decl,
336                     varbinder::Variable *var) override;
337    void DeclareClassMethod(ir::MethodDefinition *method);
338    void MaybeAddOverload(ir::MethodDefinition *method, ir::Identifier *methodName, varbinder::Variable *found,
339                          varbinder::ClassScope *clsScope, varbinder::LocalScope *targetScope);
340
341    void VisitClassStaticBlock(ir::ClassStaticBlock *staticBlock) override;
342    void VisitBlockExpression(ir::BlockExpression *blockExpr) override;
343    void VisitImportNamespaceSpecifier(ir::ImportNamespaceSpecifier *importSpec) override;
344    void VisitImportSpecifier([[maybe_unused]] ir::ImportSpecifier *importSpec) override;
345    void VisitImportDefaultSpecifier([[maybe_unused]] ir::ImportDefaultSpecifier *importSpec) override {};
346    void VisitETSReExportDeclaration(ir::ETSReExportDeclaration *reExport) override;
347    void VisitETSParameterExpression(ir::ETSParameterExpression *paramExpr) override;
348    void VisitETSImportDeclaration(ir::ETSImportDeclaration *importDecl) override;
349    void VisitTSEnumMember(ir::TSEnumMember *enumMember) override;
350    void VisitMethodDefinition(ir::MethodDefinition *method) override;
351    void VisitETSFunctionType(ir::ETSFunctionType *funcType) override;
352    void VisitETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *newClassExpr) override;
353    void VisitTSTypeParameter(ir::TSTypeParameter *typeParam) override;
354    void VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration *interfaceDecl) override;
355    void VisitTSEnumDeclaration(ir::TSEnumDeclaration *enumDecl) override;
356    void VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration *typeAlias) override;
357    void VisitClassDefinition(ir::ClassDefinition *classDef) override;
358    void VisitTSInterfaceBody(ir::TSInterfaceBody *interfBody) override;
359    void VisitClassProperty(ir::ClassProperty *classProp) override;
360    void VisitBreakStatement(ir::BreakStatement *stmt) override;
361    void VisitContinueStatement(ir::ContinueStatement *stmt) override;
362    void AttachLabelToScope(ir::AstNode *node) override;
363    void VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowExpr) override
364    {
365        Iterate(arrowExpr);
366    }
367
368    util::StringView FormInterfaceOrEnumDeclarationIdBinding(ir::Identifier *id) override
369    {
370        return id->Name();
371    }
372
373    static void AddGlobalToBinder(parser::Program *program);
374
375    void FilterInterfaceOverloads(ArenaVector<ir::AstNode *> &props);
376
377    void FilterOverloads(ArenaVector<ir::AstNode *> &props);
378};
379
380class InitScopesPhaseAS : public ScopesInitPhase {
381public:
382    NO_COPY_SEMANTIC(InitScopesPhaseAS);
383    NO_MOVE_SEMANTIC(InitScopesPhaseAS);
384    InitScopesPhaseAS() = default;
385    ~InitScopesPhaseAS() override = default;
386
387private:
388    void VisitArrowFunctionExpression(ir::ArrowFunctionExpression *arrowExpr) override;
389    void VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl) override;
390};
391}  // namespace ark::es2panda::compiler
392
393#endif
394