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 29namespace panda::es2panda::ir { 30 31bool 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 96void AssignmentExpression::Iterate(const NodeTraverser &cb) const 97{ 98 cb(left_); 99 cb(right_); 100} 101 102void 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 111void 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 160void 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 168checker::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 237void 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