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