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 declare_(data.declare),
32 lang_(data.lang),
33 returnStatements_(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 for (auto *param : Params()) {
73 params.push_back(param->Clone(allocator, nullptr)->AsExpression());
74 }
75 auto *res = util::NodeAllocator::ForceSetParent<ScriptFunction>(
76 allocator, allocator,
77 ScriptFunctionData {
78 body_ != nullptr ? body_->Clone(allocator, nullptr) : nullptr,
79 FunctionSignature {
80 TypeParams() != nullptr ? TypeParams()->Clone(allocator, nullptr)->AsTSTypeParameterDeclaration()
81 : nullptr,
82 std::move(params),
83 ReturnTypeAnnotation() != nullptr ? ReturnTypeAnnotation()->Clone(allocator, nullptr)->AsTypeNode()
84 : nullptr},
85 funcFlags_, flags_, declare_, lang_});
86 res->SetParent(parent);
87 return res;
88 }
89
TransformChildren(const NodeTransformer & cb,std::string_view const transformationName)90 void ScriptFunction::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)
91 {
92 if (id_ != nullptr) {
93 if (auto *transformedNode = cb(id_); id_ != transformedNode) {
94 id_->SetTransformedNode(transformationName, transformedNode);
95 id_ = transformedNode->AsIdentifier();
96 }
97 }
98
99 irSignature_.TransformChildren(cb, transformationName);
100
101 if (body_ != nullptr) {
102 if (auto *transformedNode = cb(body_); body_ != transformedNode) {
103 body_->SetTransformedNode(transformationName, transformedNode);
104 body_ = transformedNode;
105 }
106 }
107 }
108
Iterate(const NodeTraverser & cb) const109 void ScriptFunction::Iterate(const NodeTraverser &cb) const
110 {
111 if (id_ != nullptr) {
112 cb(id_);
113 }
114 irSignature_.Iterate(cb);
115 if (body_ != nullptr) {
116 cb(body_);
117 }
118 }
119
SetReturnTypeAnnotation(TypeNode * node)120 void ScriptFunction::SetReturnTypeAnnotation(TypeNode *node) noexcept
121 {
122 irSignature_.SetReturnType(node);
123 if (node != nullptr) {
124 node->SetParent(this);
125 }
126 }
127
Dump(ir::AstDumper * dumper) const128 void ScriptFunction::Dump(ir::AstDumper *dumper) const
129 {
130 dumper->Add({{"type", "ScriptFunction"},
131 {"id", AstDumper::Nullish(id_)},
132 {"generator", IsGenerator()},
133 {"async", IsAsyncFunc()},
134 {"expression", ((funcFlags_ & ir::ScriptFunctionFlags::EXPRESSION) != 0)},
135 {"params", irSignature_.Params()},
136 {"returnType", AstDumper::Optional(irSignature_.ReturnType())},
137 {"typeParameters", AstDumper::Optional(irSignature_.TypeParams())},
138 {"declare", AstDumper::Optional(declare_)},
139 {"body", AstDumper::Optional(body_)}});
140
141 if (IsThrowing()) {
142 dumper->Add({"throwMarker", "throws"});
143 } else if (IsRethrowing()) {
144 dumper->Add({"throwMarker", "rethrows"});
145 }
146 }
147
Dump(ir::SrcDumper * dumper) const148 void ScriptFunction::Dump(ir::SrcDumper *dumper) const
149 {
150 if (TypeParams() != nullptr) {
151 dumper->Add("<");
152 TypeParams()->Dump(dumper);
153 dumper->Add(">");
154 }
155 dumper->Add("(");
156 for (auto param : Params()) {
157 param->Dump(dumper);
158 if (param != Params().back()) {
159 dumper->Add(", ");
160 }
161 }
162 dumper->Add(")");
163 if (ReturnTypeAnnotation() != nullptr) {
164 dumper->Add(": ");
165 ReturnTypeAnnotation()->Dump(dumper);
166 }
167
168 if (IsThrowing()) {
169 dumper->Add(" throws");
170 }
171
172 if (HasBody()) {
173 if (body_->IsBlockStatement()) {
174 dumper->Add(" {");
175 if (!body_->AsBlockStatement()->Statements().empty()) {
176 dumper->IncrIndent();
177 dumper->Endl();
178 body_->Dump(dumper);
179 dumper->DecrIndent();
180 dumper->Endl();
181 }
182 dumper->Add("}");
183 } else {
184 dumper->Add(" ");
185 body_->Dump(dumper);
186 }
187 }
188 if (!IsArrow()) {
189 dumper->Endl();
190 }
191 }
192
Compile(compiler::PandaGen * pg) const193 void ScriptFunction::Compile(compiler::PandaGen *pg) const
194 {
195 pg->GetAstCompiler()->Compile(this);
196 }
Compile(compiler::ETSGen * etsg) const197 void ScriptFunction::Compile(compiler::ETSGen *etsg) const
198 {
199 etsg->GetAstCompiler()->Compile(this);
200 }
201
Check(checker::TSChecker * checker)202 checker::Type *ScriptFunction::Check(checker::TSChecker *checker)
203 {
204 return checker->GetAnalyzer()->Check(this);
205 }
206
Check(checker::ETSChecker * checker)207 checker::Type *ScriptFunction::Check(checker::ETSChecker *checker)
208 {
209 return checker->GetAnalyzer()->Check(this);
210 }
211 } // namespace ark::es2panda::ir
212