• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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