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