1 /**
2 * Copyright (c) 2021 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 "callExpression.h"
17
18 #include <util/helpers.h>
19 #include <compiler/core/pandagen.h>
20 #include <compiler/core/regScope.h>
21 #include <typescript/checker.h>
22 #include <typescript/types/objectType.h>
23 #include <typescript/types/signature.h>
24 #include <typescript/types/type.h>
25 #include <ir/astDump.h>
26 #include <ir/expressions/chainExpression.h>
27 #include <ir/expressions/memberExpression.h>
28 #include <ir/ts/tsTypeParameterInstantiation.h>
29
30 namespace panda::es2panda::ir {
31
Iterate(const NodeTraverser & cb) const32 void CallExpression::Iterate(const NodeTraverser &cb) const
33 {
34 cb(callee_);
35
36 if (typeParams_) {
37 cb(typeParams_);
38 }
39
40 for (auto *it : arguments_) {
41 cb(it);
42 }
43 }
44
Dump(ir::AstDumper * dumper) const45 void CallExpression::Dump(ir::AstDumper *dumper) const
46 {
47 dumper->Add({{"type", "CallExpression"},
48 {"callee", callee_},
49 {"arguments", arguments_},
50 {"optional", optional_},
51 {"typeParameters", AstDumper::Optional(typeParams_)}});
52 }
53
CreateSpreadArguments(compiler::PandaGen * pg) const54 compiler::VReg CallExpression::CreateSpreadArguments(compiler::PandaGen *pg) const
55 {
56 compiler::VReg argsObj = pg->AllocReg();
57 pg->CreateArray(this, arguments_, argsObj);
58
59 return argsObj;
60 }
61
Compile(compiler::PandaGen * pg) const62 void CallExpression::Compile(compiler::PandaGen *pg) const
63 {
64 if (callee_->IsCallExpression() || callee_->IsNewExpression()) {
65 if (pg->TryCompileFunctionCallOrNewExpression(callee_)) {
66 return;
67 }
68 }
69
70 compiler::RegScope rs(pg);
71 bool containsSpread = util::Helpers::ContainSpreadElement(arguments_);
72
73 if (callee_->IsSuperExpression()) {
74 if (containsSpread) {
75 compiler::RegScope paramScope(pg);
76 compiler::VReg argsObj = CreateSpreadArguments(pg);
77
78 pg->GetFunctionObject(this);
79 pg->SuperCallSpread(this, argsObj);
80 } else {
81 compiler::RegScope paramScope(pg);
82 compiler::VReg argStart {};
83
84 if (arguments_.empty()) {
85 argStart = pg->AllocReg();
86 pg->LoadConst(this, compiler::Constant::JS_UNDEFINED);
87 pg->StoreAccumulator(this, argStart);
88 } else {
89 argStart = pg->NextReg();
90 }
91
92 for (const auto *it : arguments_) {
93 compiler::VReg arg = pg->AllocReg();
94 it->Compile(pg);
95 pg->StoreAccumulator(it, arg);
96 }
97
98 pg->SuperCall(this, argStart, arguments_.size());
99 }
100
101 compiler::VReg newThis = pg->AllocReg();
102 pg->StoreAccumulator(this, newThis);
103
104 pg->GetThis(this);
105 pg->ThrowIfSuperNotCorrectCall(this, 1);
106
107 pg->LoadAccumulator(this, newThis);
108 pg->SetThis(this);
109 return;
110 }
111
112 compiler::VReg callee = pg->AllocReg();
113 bool hasThis = false;
114 compiler::VReg thisReg {};
115
116 if (callee_->IsMemberExpression()) {
117 hasThis = true;
118 thisReg = pg->AllocReg();
119
120 compiler::RegScope mrs(pg);
121 callee_->AsMemberExpression()->Compile(pg, thisReg);
122 } else if (callee_->IsChainExpression()) {
123 hasThis = true;
124 callee_->AsChainExpression()->Compile(pg);
125 } else {
126 callee_->Compile(pg);
127 }
128
129 pg->StoreAccumulator(this, callee);
130 pg->GetOptionalChain()->CheckNullish(optional_, callee);
131
132 if (containsSpread) {
133 if (!hasThis) {
134 thisReg = pg->AllocReg();
135 pg->LoadConst(this, compiler::Constant::JS_UNDEFINED);
136 pg->StoreAccumulator(this, thisReg);
137 }
138
139 compiler::VReg argsObj = CreateSpreadArguments(pg);
140 pg->CallSpread(this, callee, thisReg, argsObj);
141 return;
142 }
143
144 for (const auto *it : arguments_) {
145 it->Compile(pg);
146 compiler::VReg arg = pg->AllocReg();
147 pg->StoreAccumulator(it, arg);
148 }
149
150 if (hasThis) {
151 pg->CallThis(this, callee, static_cast<int64_t>(arguments_.size() + 1));
152 return;
153 }
154
155 pg->Call(this, callee, arguments_.size());
156 }
157
Check(checker::Checker * checker) const158 checker::Type *CallExpression::Check(checker::Checker *checker) const
159 {
160 checker::Type *calleeType = callee_->Check(checker);
161
162 // TODO(aszilagyi): handle optional chain
163 if (calleeType->IsObjectType()) {
164 checker::ObjectType *calleeObj = calleeType->AsObjectType();
165 return checker->resolveCallOrNewExpression(calleeObj->CallSignatures(), arguments_, Start());
166 }
167
168 checker->ThrowTypeError("This expression is not callable.", Start());
169 return nullptr;
170 }
171
UpdateSelf(const NodeUpdater & cb,binder::Binder * binder)172 void CallExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
173 {
174 callee_ = std::get<ir::AstNode *>(cb(callee_))->AsExpression();
175
176 if (typeParams_) {
177 typeParams_ = std::get<ir::AstNode *>(cb(typeParams_))->AsTSTypeParameterInstantiation();
178 }
179
180 for (auto iter = arguments_.begin(); iter != arguments_.end(); iter++) {
181 *iter = std::get<ir::AstNode *>(cb(*iter))->AsExpression();
182 }
183 }
184
185 } // namespace panda::es2panda::ir
186