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 #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
24 namespace ark::es2panda::ir {
25
ScriptFunction(ArenaAllocator * allocator,ScriptFunctionData && data)26 ScriptFunction::ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data)
27 : AstNode(AstNodeType::SCRIPT_FUNCTION, data.flags),
28 irSignature_(std::move(data.signature)),
29 body_(data.body),
30 funcFlags_(data.funcFlags),
31 lang_(data.lang),
32 returnStatements_(allocator->Adapter()),
33 annotations_(allocator->Adapter())
34 {
35 for (auto *param : irSignature_.Params()) {
36 param->SetParent(this);
37 }
38
39 if (auto *returnType = irSignature_.ReturnType(); returnType != nullptr) {
40 returnType->SetParent(this);
41 }
42
43 if (auto *typeParams = irSignature_.TypeParams(); typeParams != nullptr) {
44 typeParams->SetParent(this);
45 }
46 }
47
FormalParamsLength() const48 std::size_t ScriptFunction::FormalParamsLength() const noexcept
49 {
50 std::size_t length = 0U;
51
52 for (const auto *param : irSignature_.Params()) {
53 if (param->IsRestElement() || param->IsAssignmentPattern()) {
54 break;
55 }
56
57 ++length;
58 }
59
60 return length;
61 }
62
SetIdent(Identifier * id)63 void ScriptFunction::SetIdent(Identifier *id) noexcept
64 {
65 id_ = id;
66 id_->SetParent(this);
67 }
68
Clone(ArenaAllocator * allocator,AstNode * parent)69 ScriptFunction *ScriptFunction::Clone(ArenaAllocator *allocator, AstNode *parent)
70 {
71 ArenaVector<Expression *> params {allocator->Adapter()};
72 ArenaVector<AnnotationUsage *> annotationUsages {allocator->Adapter()};
73 for (auto *param : Params()) {
74 params.push_back(param->Clone(allocator, nullptr)->AsExpression());
75 }
76 for (auto *annotationUsage : Annotations()) {
77 annotationUsages.push_back(annotationUsage->Clone(allocator, nullptr)->AsAnnotationUsage());
78 }
79 auto *res = util::NodeAllocator::ForceSetParent<ScriptFunction>(
80 allocator, allocator,
81 ScriptFunctionData {
82 body_ != nullptr ? body_->Clone(allocator, nullptr) : nullptr,
83 FunctionSignature {
84 TypeParams() != nullptr ? TypeParams()->Clone(allocator, nullptr)->AsTSTypeParameterDeclaration()
85 : nullptr,
86 std::move(params),
87 ReturnTypeAnnotation() != nullptr ? ReturnTypeAnnotation()->Clone(allocator, nullptr)->AsTypeNode()
88 : nullptr},
89 funcFlags_, flags_, lang_});
90 res->SetParent(parent);
91 res->SetAnnotations(std::move(annotationUsages));
92 return res;
93 }
94
TransformChildren(const NodeTransformer & cb,std::string_view const transformationName)95 void ScriptFunction::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)
96 {
97 if (id_ != nullptr) {
98 if (auto *transformedNode = cb(id_); id_ != transformedNode) {
99 id_->SetTransformedNode(transformationName, transformedNode);
100 id_ = transformedNode->AsIdentifier();
101 }
102 }
103
104 irSignature_.TransformChildren(cb, transformationName);
105
106 if (body_ != nullptr) {
107 if (auto *transformedNode = cb(body_); body_ != transformedNode) {
108 body_->SetTransformedNode(transformationName, transformedNode);
109 body_ = transformedNode;
110 }
111 }
112
113 for (auto *&it : annotations_) {
114 if (auto *transformedNode = cb(it); it != transformedNode) {
115 it->SetTransformedNode(transformationName, transformedNode);
116 it = transformedNode->AsAnnotationUsage();
117 }
118 }
119 }
120
Iterate(const NodeTraverser & cb) const121 void ScriptFunction::Iterate(const NodeTraverser &cb) const
122 {
123 if (id_ != nullptr) {
124 cb(id_);
125 }
126 irSignature_.Iterate(cb);
127 if (body_ != nullptr) {
128 cb(body_);
129 }
130 for (auto *it : annotations_) {
131 cb(it);
132 }
133 }
134
SetReturnTypeAnnotation(TypeNode * node)135 void ScriptFunction::SetReturnTypeAnnotation(TypeNode *node) noexcept
136 {
137 irSignature_.SetReturnType(node);
138 if (node != nullptr) {
139 node->SetParent(this);
140 }
141 }
142
Dump(ir::AstDumper * dumper) const143 void ScriptFunction::Dump(ir::AstDumper *dumper) const
144 {
145 const char *throwMarker = nullptr;
146 if (IsThrowing()) {
147 throwMarker = "throws";
148 } else if (IsRethrowing()) {
149 throwMarker = "rethrows";
150 }
151 dumper->Add({{"type", "ScriptFunction"},
152 {"id", AstDumper::Nullish(id_)},
153 {"generator", IsGenerator()},
154 {"async", IsAsyncFunc()},
155 {"expression", ((funcFlags_ & ir::ScriptFunctionFlags::EXPRESSION) != 0)},
156 {"params", irSignature_.Params()},
157 {"returnType", AstDumper::Optional(irSignature_.ReturnType())},
158 {"typeParameters", AstDumper::Optional(irSignature_.TypeParams())},
159 {"declare", AstDumper::Optional(IsDeclare())},
160 {"body", AstDumper::Optional(body_)},
161 {"annotations", AstDumper::Optional(annotations_)},
162 {"throwMarker", AstDumper::Optional(throwMarker)}});
163 }
164
Dump(ir::SrcDumper * dumper) const165 void ScriptFunction::Dump(ir::SrcDumper *dumper) const
166 {
167 if (TypeParams() != nullptr) {
168 dumper->Add("<");
169 TypeParams()->Dump(dumper);
170 dumper->Add(">");
171 }
172 dumper->Add("(");
173 for (auto param : Params()) {
174 if (param->IsETSParameterExpression() && param->AsETSParameterExpression()->Ident() != nullptr &&
175 param->AsETSParameterExpression()->Ident()->Name() == varbinder::VarBinder::MANDATORY_PARAM_THIS) {
176 continue;
177 }
178 param->Dump(dumper);
179 if (param != Params().back()) {
180 dumper->Add(", ");
181 }
182 }
183 dumper->Add(")");
184 if (ReturnTypeAnnotation() != nullptr) {
185 dumper->Add(": ");
186 ReturnTypeAnnotation()->Dump(dumper);
187 }
188
189 if (IsThrowing()) {
190 dumper->Add(" throws");
191 } else if (IsRethrowing()) {
192 dumper->Add(" rethrows");
193 }
194
195 if (HasBody()) {
196 if (IsArrow()) {
197 dumper->Add(" =>");
198 }
199 if (body_->IsBlockStatement()) {
200 dumper->Add(" {");
201 if (!body_->AsBlockStatement()->Statements().empty()) {
202 dumper->IncrIndent();
203 dumper->Endl();
204 body_->Dump(dumper);
205 dumper->DecrIndent();
206 dumper->Endl();
207 }
208 dumper->Add("}");
209 } else {
210 dumper->Add(" ");
211 body_->Dump(dumper);
212 }
213 }
214 if (!IsArrow()) {
215 dumper->Endl();
216 }
217 }
218
Compile(compiler::PandaGen * pg) const219 void ScriptFunction::Compile(compiler::PandaGen *pg) const
220 {
221 pg->GetAstCompiler()->Compile(this);
222 }
Compile(compiler::ETSGen * etsg) const223 void ScriptFunction::Compile(compiler::ETSGen *etsg) const
224 {
225 etsg->GetAstCompiler()->Compile(this);
226 }
227
Check(checker::TSChecker * checker)228 checker::Type *ScriptFunction::Check(checker::TSChecker *checker)
229 {
230 return checker->GetAnalyzer()->Check(this);
231 }
232
Check(checker::ETSChecker * checker)233 checker::Type *ScriptFunction::Check(checker::ETSChecker *checker)
234 {
235 return checker->GetAnalyzer()->Check(this);
236 }
237 } // namespace ark::es2panda::ir
238