• 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 "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