• 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 #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