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 #include "scriptFunction.h"
17
18 #include "checker/TSchecker.h"
19 #include "compiler/core/ETSGen.h"
20 #include "compiler/core/pandagen.h"
21 #include "ir/astDump.h"
22 #include "ir/srcDump.h"
23 #include "mem/arena_allocator.h"
24 #include "utils/arena_containers.h"
25
26 namespace ark::es2panda::ir {
27
ScriptFunction(ArenaAllocator * allocator,ScriptFunctionData && data)28 ScriptFunction::ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data)
29 : JsDocAllowed<AnnotationAllowed<AstNode>>(AstNodeType::SCRIPT_FUNCTION, data.flags, allocator),
30 irSignature_(std::move(data.signature)),
31 body_(data.body),
32 funcFlags_(data.funcFlags),
33 lang_(data.lang),
34 returnStatements_(allocator->Adapter())
35 {
36 for (auto *param : irSignature_.Params()) {
37 param->SetParent(this);
38 }
39
40 if (auto *returnType = irSignature_.ReturnType(); returnType != nullptr) {
41 returnType->SetParent(this);
42 }
43
44 if (auto *typeParams = irSignature_.TypeParams(); typeParams != nullptr) {
45 typeParams->SetParent(this);
46 }
47 }
48
FormalParamsLength() const49 std::size_t ScriptFunction::FormalParamsLength() const noexcept
50 {
51 std::size_t length = 0U;
52
53 for (const auto *param : irSignature_.Params()) {
54 if (param->IsRestElement() || param->IsAssignmentPattern()) {
55 break;
56 }
57
58 ++length;
59 }
60
61 return length;
62 }
63
SetIdent(Identifier * id)64 void ScriptFunction::SetIdent(Identifier *id) noexcept
65 {
66 id_ = id;
67 ES2PANDA_ASSERT(id_ != nullptr);
68 id_->SetParent(this);
69 }
70
Clone(ArenaAllocator * allocator,AstNode * parent)71 ScriptFunction *ScriptFunction::Clone(ArenaAllocator *allocator, AstNode *parent)
72 {
73 ArenaVector<ir::Expression *> params {allocator->Adapter()};
74 ArenaVector<AnnotationUsage *> annotationUsages {allocator->Adapter()};
75 for (auto *param : Params()) {
76 params.push_back(param->Clone(allocator, nullptr)->AsExpression());
77 }
78 AnnotationUsage *clonedAnnotationUsage;
79 for (auto *annotationUsage : Annotations()) {
80 clonedAnnotationUsage = annotationUsage->Clone(allocator, nullptr);
81 ES2PANDA_ASSERT(clonedAnnotationUsage != nullptr);
82 annotationUsages.push_back(clonedAnnotationUsage->AsAnnotationUsage());
83 }
84 auto *res = util::NodeAllocator::ForceSetParent<ScriptFunction>(
85 allocator, allocator,
86 ScriptFunctionData {
87 body_ != nullptr ? body_->Clone(allocator, nullptr) : nullptr,
88 FunctionSignature {
89 TypeParams() != nullptr ? TypeParams()->Clone(allocator, nullptr)->AsTSTypeParameterDeclaration()
90 : nullptr,
91 std::move(params),
92 ReturnTypeAnnotation() != nullptr ? ReturnTypeAnnotation()->Clone(allocator, nullptr)->AsTypeNode()
93 : nullptr,
94 HasReceiver()},
95 funcFlags_, flags_, lang_});
96 ES2PANDA_ASSERT(res != nullptr);
97 res->SetParent(parent);
98 res->SetAnnotations(std::move(annotationUsages));
99 return res;
100 }
101
TransformChildren(const NodeTransformer & cb,std::string_view const transformationName)102 void ScriptFunction::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)
103 {
104 if (id_ != nullptr) {
105 if (auto *transformedNode = cb(id_); id_ != transformedNode) {
106 id_->SetTransformedNode(transformationName, transformedNode);
107 id_ = transformedNode->AsIdentifier();
108 }
109 }
110
111 irSignature_.TransformChildren(cb, transformationName);
112
113 if (body_ != nullptr) {
114 if (auto *transformedNode = cb(body_); body_ != transformedNode) {
115 body_->SetTransformedNode(transformationName, transformedNode);
116 body_ = transformedNode;
117 }
118 }
119
120 for (auto *&it : VectorIterationGuard(Annotations())) {
121 if (auto *transformedNode = cb(it); it != transformedNode) {
122 it->SetTransformedNode(transformationName, transformedNode);
123 it = transformedNode->AsAnnotationUsage();
124 }
125 }
126 }
127
Iterate(const NodeTraverser & cb) const128 void ScriptFunction::Iterate(const NodeTraverser &cb) const
129 {
130 if (id_ != nullptr) {
131 cb(id_);
132 }
133 irSignature_.Iterate(cb);
134 if (body_ != nullptr) {
135 cb(body_);
136 }
137 for (auto *it : VectorIterationGuard(Annotations())) {
138 cb(it);
139 }
140 }
141
SetReturnTypeAnnotation(TypeNode * node)142 void ScriptFunction::SetReturnTypeAnnotation(TypeNode *node) noexcept
143 {
144 irSignature_.SetReturnType(node);
145 if (node != nullptr) {
146 node->SetParent(this);
147 }
148 }
149
Dump(ir::AstDumper * dumper) const150 void ScriptFunction::Dump(ir::AstDumper *dumper) const
151 {
152 const char *throwMarker = nullptr;
153 if (IsThrowing()) {
154 throwMarker = "throws";
155 } else if (IsRethrowing()) {
156 throwMarker = "rethrows";
157 }
158 dumper->Add({{"type", "ScriptFunction"},
159 {"id", AstDumper::Nullish(id_)},
160 {"generator", IsGenerator()},
161 {"async", IsAsyncFunc()},
162 {"expression", ((funcFlags_ & ir::ScriptFunctionFlags::EXPRESSION) != 0)},
163 {"params", irSignature_.Params()},
164 {"returnType", AstDumper::Optional(irSignature_.ReturnType())},
165 {"typeParameters", AstDumper::Optional(irSignature_.TypeParams())},
166 {"declare", AstDumper::Optional(IsDeclare())},
167 {"body", AstDumper::Optional(body_)},
168 {"annotations", AstDumper::Optional(Annotations())},
169 {"throwMarker", AstDumper::Optional(throwMarker)}});
170 }
171
DumpCheckerTypeForDeclGen(ir::SrcDumper * dumper) const172 void ScriptFunction::DumpCheckerTypeForDeclGen(ir::SrcDumper *dumper) const
173 {
174 if (!dumper->IsDeclgen()) {
175 return;
176 }
177
178 if (IsConstructor()) {
179 return;
180 }
181
182 if (Signature() == nullptr) {
183 return;
184 }
185
186 if (Signature()->ReturnType() == nullptr) {
187 return;
188 }
189
190 auto typeStr = dumper->IsIsolatedDeclgen() ? GetIsolatedDeclgenReturnType() : Signature()->ReturnType()->ToString();
191
192 dumper->Add(": ");
193 dumper->Add(typeStr);
194
195 dumper->PushTask([dumper, typeStr] { dumper->DumpNode(typeStr); });
196 }
197
Dump(ir::SrcDumper * dumper) const198 void ScriptFunction::Dump(ir::SrcDumper *dumper) const
199 {
200 if (TypeParams() != nullptr) {
201 dumper->Add("<");
202 TypeParams()->Dump(dumper);
203 dumper->Add(">");
204 }
205 dumper->Add("(");
206 for (auto param : Params()) {
207 param->Dump(dumper);
208 if (param != Params().back()) {
209 dumper->Add(", ");
210 }
211 }
212 dumper->Add(")");
213 if (ReturnTypeAnnotation() != nullptr && !dumper->IsDeclgen()) {
214 dumper->Add(": ");
215 ReturnTypeAnnotation()->Dump(dumper);
216 }
217 DumpCheckerTypeForDeclGen(dumper);
218 if (IsThrowing()) {
219 dumper->Add(" throws");
220 } else if (IsRethrowing()) {
221 dumper->Add(" rethrows");
222 }
223 if (dumper->IsDeclgen()) {
224 dumper->Add(";");
225 dumper->Endl();
226 return;
227 }
228 DumpBody(dumper);
229 }
230
DumpBody(ir::SrcDumper * dumper) const231 void ScriptFunction::DumpBody(ir::SrcDumper *dumper) const
232 {
233 if (!HasBody()) {
234 dumper->Endl();
235 return;
236 }
237
238 if (IsArrow()) {
239 dumper->Add(" =>");
240 }
241
242 if (body_->IsBlockStatement()) {
243 dumper->Add(" {");
244 const auto &statements = body_->AsBlockStatement()->Statements();
245 if (!statements.empty()) {
246 dumper->IncrIndent();
247 dumper->Endl();
248 body_->Dump(dumper);
249 dumper->DecrIndent();
250 dumper->Endl();
251 }
252 dumper->Add("}");
253 } else {
254 dumper->Add(" ");
255 body_->Dump(dumper);
256 }
257
258 if (!IsArrow()) {
259 dumper->Endl();
260 }
261 }
262
Compile(compiler::PandaGen * pg) const263 void ScriptFunction::Compile(compiler::PandaGen *pg) const
264 {
265 pg->GetAstCompiler()->Compile(this);
266 }
Compile(compiler::ETSGen * etsg) const267 void ScriptFunction::Compile(compiler::ETSGen *etsg) const
268 {
269 etsg->GetAstCompiler()->Compile(this);
270 }
271
Check(checker::TSChecker * checker)272 checker::Type *ScriptFunction::Check(checker::TSChecker *checker)
273 {
274 return checker->GetAnalyzer()->Check(this);
275 }
276
Check(checker::ETSChecker * checker)277 checker::VerifiedType ScriptFunction::Check(checker::ETSChecker *checker)
278 {
279 return {this, checker->GetAnalyzer()->Check(this)};
280 }
281
Construct(ArenaAllocator * allocator)282 ScriptFunction *ScriptFunction::Construct(ArenaAllocator *allocator)
283 {
284 auto adapter = allocator->Adapter();
285 return allocator->New<ScriptFunction>(
286 allocator,
287 ScriptFunctionData {nullptr, FunctionSignature(nullptr, ArenaVector<Expression *>(adapter), nullptr)});
288 }
289
CopyTo(AstNode * other) const290 void ScriptFunction::CopyTo(AstNode *other) const
291 {
292 auto otherImpl = other->AsScriptFunction();
293
294 otherImpl->id_ = id_;
295
296 otherImpl->irSignature_.CopyFrom(irSignature_);
297
298 otherImpl->body_ = body_;
299 otherImpl->scope_ = scope_;
300 otherImpl->funcFlags_ = funcFlags_;
301 otherImpl->signature_ = signature_;
302 otherImpl->preferredReturnType_ = preferredReturnType_;
303 otherImpl->lang_ = lang_;
304 otherImpl->returnStatements_ = returnStatements_;
305 otherImpl->isolatedDeclGenInferType_ = isolatedDeclGenInferType_;
306
307 JsDocAllowed<AnnotationAllowed<AstNode>>::CopyTo(other);
308 }
309 } // namespace ark::es2panda::ir
310