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 "assignmentExpression.h"
17
18 #include <compiler/base/lreference.h>
19 #include <compiler/core/pandagen.h>
20 #include <typescript/core/destructuringContext.h>
21 #include <ir/astDump.h>
22 #include <ir/base/spreadElement.h>
23 #include <ir/expressions/arrayExpression.h>
24 #include <ir/expressions/objectExpression.h>
25 #include <ir/expressions/identifier.h>
26
27 namespace panda::es2panda::ir {
28
ConvertibleToAssignmentPattern(bool mustBePattern)29 bool AssignmentExpression::ConvertibleToAssignmentPattern(bool mustBePattern)
30 {
31 bool convResult = true;
32
33 switch (left_->Type()) {
34 case AstNodeType::ARRAY_EXPRESSION: {
35 convResult = left_->AsArrayExpression()->ConvertibleToArrayPattern();
36 break;
37 }
38 case AstNodeType::SPREAD_ELEMENT: {
39 convResult = mustBePattern && left_->AsSpreadElement()->ConvertibleToRest(false);
40 break;
41 }
42 case AstNodeType::OBJECT_EXPRESSION: {
43 convResult = left_->AsObjectExpression()->ConvertibleToObjectPattern();
44 break;
45 }
46 case AstNodeType::ASSIGNMENT_EXPRESSION: {
47 convResult = left_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(mustBePattern);
48 break;
49 }
50 case AstNodeType::META_PROPERTY_EXPRESSION:
51 case AstNodeType::CHAIN_EXPRESSION: {
52 convResult = false;
53 break;
54 }
55 default: {
56 break;
57 }
58 }
59
60 if (mustBePattern) {
61 SetType(AstNodeType::ASSIGNMENT_PATTERN);
62 }
63
64 if (!right_->IsAssignmentExpression()) {
65 return convResult;
66 }
67
68 switch (right_->Type()) {
69 case AstNodeType::ARRAY_EXPRESSION: {
70 convResult = right_->AsArrayExpression()->ConvertibleToArrayPattern();
71 break;
72 }
73 case AstNodeType::CHAIN_EXPRESSION:
74 case AstNodeType::SPREAD_ELEMENT: {
75 convResult = false;
76 break;
77 }
78 case AstNodeType::OBJECT_EXPRESSION: {
79 convResult = right_->AsObjectExpression()->ConvertibleToObjectPattern();
80 break;
81 }
82 case AstNodeType::ASSIGNMENT_EXPRESSION: {
83 convResult = right_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(false);
84 break;
85 }
86 default: {
87 break;
88 }
89 }
90
91 return convResult;
92 }
93
Iterate(const NodeTraverser & cb) const94 void AssignmentExpression::Iterate(const NodeTraverser &cb) const
95 {
96 cb(left_);
97 cb(right_);
98 }
99
Dump(ir::AstDumper * dumper) const100 void AssignmentExpression::Dump(ir::AstDumper *dumper) const
101 {
102 if (type_ == AstNodeType::ASSIGNMENT_EXPRESSION) {
103 dumper->Add({{"type", "AssignmentExpression"}, {"operator", operator_}, {"left", left_}, {"right", right_}});
104 } else {
105 dumper->Add({{"type", "AssignmentPattern"}, {"left", left_}, {"right", right_}});
106 }
107 }
108
Compile(compiler::PandaGen * pg) const109 void AssignmentExpression::Compile(compiler::PandaGen *pg) const
110 {
111 compiler::RegScope rs(pg);
112 compiler::LReference lref = compiler::LReference::CreateLRef(pg, left_, false);
113
114 if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND_EQUAL ||
115 operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR_EQUAL ||
116 operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_NULLISH_EQUAL) {
117 auto *skipRight = pg->AllocLabel();
118 auto *endLabel = pg->AllocLabel();
119 compiler::VReg lhsReg = pg->AllocReg();
120
121 lref.GetValue();
122 pg->StoreAccumulator(left_, lhsReg);
123 if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND_EQUAL) {
124 pg->BranchIfFalse(left_, skipRight);
125 } else if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR_EQUAL) {
126 pg->BranchIfTrue(left_, skipRight);
127 } else {
128 ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_NULLISH_EQUAL);
129 auto *nullish = pg->AllocLabel();
130 pg->BranchIfStrictNull(left_, nullish);
131 pg->LoadAccumulator(left_, lhsReg);
132 pg->BranchIfStrictNotUndefined(this, skipRight);
133 pg->SetLabel(left_, nullish);
134 }
135 // left = right
136 right_->Compile(pg);
137 lref.SetValue();
138 pg->Branch(this, endLabel);
139 // skip right part
140 pg->SetLabel(this, skipRight);
141 pg->LoadAccumulator(this, lhsReg);
142 pg->SetLabel(this, endLabel);
143 return;
144 } else if (operator_ != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
145 compiler::VReg lhsReg = pg->AllocReg();
146
147 lref.GetValue();
148 pg->StoreAccumulator(left_, lhsReg);
149 right_->Compile(pg);
150 pg->Binary(this, operator_, lhsReg);
151 } else {
152 right_->Compile(pg);
153 }
154
155 lref.SetValue();
156 }
157
CompilePattern(compiler::PandaGen * pg) const158 void AssignmentExpression::CompilePattern(compiler::PandaGen *pg) const
159 {
160 compiler::RegScope rs(pg);
161 compiler::LReference lref = compiler::LReference::CreateLRef(pg, left_, false);
162 right_->Compile(pg);
163 lref.SetValue();
164 }
165
Check(checker::Checker * checker) const166 checker::Type *AssignmentExpression::Check(checker::Checker *checker) const
167 {
168 if (left_->IsArrayPattern()) {
169 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
170 auto destructuringContext = checker::ArrayDestructuringContext(checker, left_, true, true, nullptr, right_);
171 destructuringContext.Start();
172 return destructuringContext.InferedType();
173 }
174
175 if (left_->IsObjectPattern()) {
176 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
177 auto destructuringContext = checker::ObjectDestructuringContext(checker, left_, true, true, nullptr, right_);
178 destructuringContext.Start();
179 return destructuringContext.InferedType();
180 }
181
182 if (left_->IsIdentifier() && left_->AsIdentifier()->Variable() &&
183 left_->AsIdentifier()->Variable()->Declaration()->IsConstDecl()) {
184 checker->ThrowTypeError({"Cannot assign to ", left_->AsIdentifier()->Name(), " because it is a constant."},
185 left_->Start());
186 }
187
188 auto *leftType = left_->Check(checker);
189
190 if (leftType->HasTypeFlag(checker::TypeFlag::READONLY)) {
191 checker->ThrowTypeError("Cannot assign to this property because it is readonly.", left_->Start());
192 }
193
194 if (operator_ == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
195 checker->ElaborateElementwise(leftType, right_, left_->Start());
196 return checker->CheckTypeCached(right_);
197 }
198
199 auto *rightType = right_->Check(checker);
200
201 switch (operator_) {
202 case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL:
203 case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL:
204 case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
205 case lexer::TokenType::PUNCTUATOR_MOD_EQUAL:
206 case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL:
207 case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL:
208 case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL:
209 case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL:
210 case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL:
211 case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL:
212 case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: {
213 return checker->CheckBinaryOperator(leftType, rightType, left_, right_, this, operator_);
214 }
215 case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
216 return checker->CheckPlusOperator(leftType, rightType, left_, right_, this, operator_);
217 }
218 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
219 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
220 return checker->CheckCompareOperator(leftType, rightType, left_, right_, this, operator_);
221 }
222 case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
223 checker->CheckAssignmentOperator(operator_, left_, leftType, rightType);
224 return rightType;
225 }
226 default: {
227 UNREACHABLE();
228 break;
229 }
230 }
231
232 return nullptr;
233 }
234
UpdateSelf(const NodeUpdater & cb,binder::Binder * binder)235 void AssignmentExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
236 {
237 left_ = std::get<ir::AstNode *>(cb(left_))->AsExpression();
238 right_ = std::get<ir::AstNode *>(cb(right_))->AsExpression();
239 }
240
241 } // namespace panda::es2panda::ir
242