1/**
2 * Copyright (c) 2021 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_PARSER_INCLUDE_AST_SCRIPT_FUNCTION_H
17#define ES2PANDA_PARSER_INCLUDE_AST_SCRIPT_FUNCTION_H
18
19#include <ir/astNode.h>
20#include <ir/expressions/identifier.h>
21#include <util/enumbitops.h>
22
23namespace panda::es2panda::compiler {
24class PandaGen;
25}  // namespace panda::es2panda::compiler
26
27namespace panda::es2panda::checker {
28class Checker;
29class Type;
30}  // namespace panda::es2panda::checker
31
32namespace panda::es2panda::binder {
33class FunctionScope;
34}  // namespace panda::es2panda::binder
35
36namespace panda::es2panda::ir {
37
38class TSTypeParameterDeclaration;
39
40class ScriptFunction : public AstNode {
41public:
42    explicit ScriptFunction(binder::FunctionScope *scope, ArenaVector<Expression *> &&params,
43                            TSTypeParameterDeclaration *typeParams, AstNode *body, Expression *returnTypeAnnotation,
44                            ir::ScriptFunctionFlags flags, bool declare, bool isTsFunction)
45        : AstNode(AstNodeType::SCRIPT_FUNCTION),
46          scope_(scope),
47          id_(nullptr),
48          params_(std::move(params)),
49          typeParams_(typeParams),
50          body_(body),
51          returnTypeAnnotation_(returnTypeAnnotation),
52          flags_(flags),
53          declare_(declare),
54          exportDefault_(false)
55    {
56        thisParam_ = nullptr;
57        if (isTsFunction && !params_.empty()) {
58            auto *firstParam = params_.front();
59            if (firstParam->IsIdentifier() && firstParam->AsIdentifier()->Name().Is(THIS_PARAM)) {
60                thisParam_ = firstParam;
61                params_.erase(params_.begin());
62                scope_->ParamScope()->RemoveThisParam(THIS_PARAM);
63                scope_->Bindings().erase(THIS_PARAM);
64            }
65        }
66    }
67
68    const Identifier *Id() const
69    {
70        return id_;
71    }
72
73    Identifier *Id()
74    {
75        return id_;
76    }
77
78    const ArenaVector<Expression *> &Params() const
79    {
80        return params_;
81    }
82
83    ArenaVector<Expression *> &Params()
84    {
85        return params_;
86    }
87
88    const TSTypeParameterDeclaration *TypeParams() const
89    {
90        return typeParams_;
91    }
92
93    TSTypeParameterDeclaration *TypeParams()
94    {
95        return typeParams_;
96    }
97
98    const Expression *ThisParams() const
99    {
100        return thisParam_;
101    }
102
103    Expression *ThisParams()
104    {
105        return thisParam_;
106    }
107
108    const AstNode *Body() const
109    {
110        return body_;
111    }
112
113    AstNode *Body()
114    {
115        return body_;
116    }
117
118    const Expression *ReturnTypeAnnotation() const
119    {
120        return returnTypeAnnotation_;
121    }
122
123    Expression *ReturnTypeAnnotation()
124    {
125        return returnTypeAnnotation_;
126    }
127
128    bool IsGenerator() const
129    {
130        return (flags_ & ir::ScriptFunctionFlags::GENERATOR) != 0;
131    }
132
133    bool IsAsync() const
134    {
135        return (flags_ & ir::ScriptFunctionFlags::ASYNC) != 0;
136    }
137
138    bool IsArrow() const
139    {
140        return (flags_ & ir::ScriptFunctionFlags::ARROW) != 0;
141    }
142
143    bool IsOverload() const
144    {
145        return (flags_ & ir::ScriptFunctionFlags::OVERLOAD) != 0;
146    }
147
148    bool IsConstructor() const
149    {
150        return (flags_ & ir::ScriptFunctionFlags::CONSTRUCTOR) != 0;
151    }
152
153    bool IsStaticInitializer() const
154    {
155        return (flags_ & ir::ScriptFunctionFlags::STATIC_INITIALIZER) != 0;
156    }
157
158    bool IsInstanceInitializer() const
159    {
160        return (flags_ & ir::ScriptFunctionFlags::INSTANCE_INITIALIZER) != 0;
161    }
162
163    bool IsMethod() const
164    {
165        return (flags_ & ir::ScriptFunctionFlags::METHOD) != 0 || IsInstanceInitializer() || IsStaticInitializer();
166    }
167
168    bool FunctionBodyIsExpression() const
169    {
170        return (flags_ & ir::ScriptFunctionFlags::EXPRESSION) != 0;
171    }
172
173    bool Declare() const
174    {
175        return declare_;
176    }
177
178    void SetIdent(Identifier *id)
179    {
180        id_ = id;
181    }
182
183    void SetAsExportDefault()
184    {
185        exportDefault_ = true;
186    }
187
188    void AddFlag(ir::ScriptFunctionFlags flags)
189    {
190        flags_ |= flags;
191    }
192
193    bool HasFlag(ir::ScriptFunctionFlags flag) const
194    {
195        return (flags_ & flag) != 0;
196    }
197
198    void SetInSendable()
199    {
200        inSendable_ = true;
201    }
202
203    size_t FormalParamsLength() const;
204    util::StringView GetName() const;
205
206    binder::FunctionScope *Scope() const
207    {
208        return scope_;
209    }
210
211    bool IsConcurrent() const
212    {
213        return (flags_ & ir::ScriptFunctionFlags::CONCURRENT) != 0;
214    }
215
216    bool IsSendable() const
217    {
218        return (flags_ & ir::ScriptFunctionFlags::SENDABLE) != 0;
219    }
220
221    bool CanBeConcurrent() const
222    {
223        return !(IsGenerator() || IsArrow());
224    }
225
226    void AddConcurrentModuleRequest(int moduleRequestId)
227    {
228        if (!IsConcurrent()) {
229            return;
230        }
231
232        concurrentModuleRequests_.emplace_back(moduleRequestId);
233    }
234
235    std::vector<int> GetConcurrentModuleRequests() const
236    {
237        return concurrentModuleRequests_;
238    }
239
240    bool InSendable() const
241    {
242        return inSendable_;
243    }
244
245    void Iterate(const NodeTraverser &cb) const override;
246    void Dump(ir::AstDumper *dumper) const override;
247    void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
248    checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
249    void UpdateSelf(const NodeUpdater &cb, binder::Binder *binder) override;
250    util::StringView SourceCode(binder::Binder *binder) const;
251
252private:
253    static constexpr std::string_view THIS_PARAM = "this";
254
255    binder::FunctionScope *scope_;
256    Identifier *id_;
257    Expression *thisParam_;
258    ArenaVector<Expression *> params_;
259    TSTypeParameterDeclaration *typeParams_;
260    AstNode *body_;
261    Expression *returnTypeAnnotation_;
262    ir::ScriptFunctionFlags flags_;
263    bool declare_;
264    bool exportDefault_;
265    std::vector<int> concurrentModuleRequests_;
266    bool inSendable_ {false};
267};
268
269}  // namespace panda::es2panda::ir
270
271#endif
272