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 "binaryExpression.h" 17 18#include <binder/variable.h> 19#include <compiler/core/pandagen.h> 20#include <compiler/core/regScope.h> 21#include <typescript/checker.h> 22#include <ir/astDump.h> 23#include <ir/base/classDefinition.h> 24#include <ir/expressions/privateIdentifier.h> 25#include <lexer/token/tokenType.h> 26 27namespace panda::es2panda::ir { 28 29void BinaryExpression::Iterate(const NodeTraverser &cb) const 30{ 31 cb(left_); 32 cb(right_); 33} 34 35void BinaryExpression::Dump(ir::AstDumper *dumper) const 36{ 37 dumper->Add({{"type", IsLogical() ? "LogicalExpression" : "BinaryExpression"}, 38 {"operator", operator_}, 39 {"left", left_}, 40 {"right", right_}}); 41} 42 43void BinaryExpression::CompileLogical(compiler::PandaGen *pg) const 44{ 45 compiler::RegScope rs(pg); 46 compiler::VReg lhs = pg->AllocReg(); 47 48 ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND || 49 operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR || 50 operator_ == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING); 51 auto *skipRight = pg->AllocLabel(); 52 auto *endLabel = pg->AllocLabel(); 53 54 // left -> acc -> lhs -> toboolean -> acc -> bool_lhs 55 left_->Compile(pg); 56 pg->StoreAccumulator(this, lhs); 57 58 if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { 59 pg->BranchIfFalse(this, skipRight); 60 } else if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR) { 61 pg->BranchIfTrue(this, skipRight); 62 } else { 63 ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING); 64 auto *nullish = pg->AllocLabel(); 65 // if lhs === null 66 pg->BranchIfStrictNull(this, nullish); 67 pg->LoadAccumulator(this, lhs); 68 // if lhs === undefined 69 pg->BranchIfStrictNotUndefined(this, skipRight); 70 pg->SetLabel(this, nullish); 71 } 72 73 // left is true/false(and/or) then right -> acc 74 right_->Compile(pg); 75 pg->Branch(this, endLabel); 76 77 // left is false/true(and/or) then lhs -> acc 78 pg->SetLabel(this, skipRight); 79 pg->LoadAccumulator(this, lhs); 80 pg->SetLabel(this, endLabel); 81} 82 83void BinaryExpression::CompilePrivateIn(compiler::PandaGen *pg) const 84{ 85 ASSERT(operator_ == lexer::TokenType::KEYW_IN); 86 auto name = left_->AsPrivateIdentifier()->Name(); 87 auto result = pg->Scope()->FindPrivateName(name); 88 89 right_->Compile(pg); 90 if (!result.result.isMethod) { 91 pg->TestIn(this, result.lexLevel, result.result.slot); 92 return; 93 } 94 // Instance private method check symbol("#method") 95 if (!result.result.isStatic) { 96 pg->TestIn(this, result.lexLevel, result.result.validateMethodSlot); 97 return; 98 } 99 // Static private method check whether equals the class object 100 compiler::RegScope rs(pg); 101 compiler::VReg rhs = pg->AllocReg(); 102 pg->StoreAccumulator(right_, rhs); 103 pg->LoadLexicalVar(this, result.lexLevel, result.result.validateMethodSlot); 104 pg->Equal(this, rhs); 105} 106 107void BinaryExpression::Compile(compiler::PandaGen *pg) const 108{ 109 if (left_->IsPrivateIdentifier()) { 110 CompilePrivateIn(pg); 111 return; 112 } 113 114 if (IsLogical()) { 115 CompileLogical(pg); 116 return; 117 } 118 119 compiler::RegScope rs(pg); 120 compiler::VReg lhs = pg->AllocReg(); 121 122 left_->Compile(pg); 123 pg->StoreAccumulator(right_, lhs); 124 right_->Compile(pg); 125 126 pg->Binary(right_, operator_, lhs); 127} 128 129checker::Type *BinaryExpression::Check(checker::Checker *checker) const 130{ 131 auto *leftType = left_->Check(checker); 132 auto *rightType = right_->Check(checker); 133 134 switch (operator_) { 135 case lexer::TokenType::PUNCTUATOR_MULTIPLY: 136 case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: 137 case lexer::TokenType::PUNCTUATOR_DIVIDE: 138 case lexer::TokenType::PUNCTUATOR_MOD: 139 case lexer::TokenType::PUNCTUATOR_MINUS: 140 case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: 141 case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: 142 case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: 143 case lexer::TokenType::PUNCTUATOR_BITWISE_AND: 144 case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: 145 case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { 146 return checker->CheckBinaryOperator(leftType, rightType, left_, right_, this, operator_); 147 } 148 case lexer::TokenType::PUNCTUATOR_PLUS: { 149 return checker->CheckPlusOperator(leftType, rightType, left_, right_, this, operator_); 150 } 151 case lexer::TokenType::PUNCTUATOR_LESS_THAN: 152 case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { 153 return checker->CheckCompareOperator(leftType, rightType, left_, right_, this, operator_); 154 } 155 case lexer::TokenType::PUNCTUATOR_EQUAL: 156 case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: 157 case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: 158 case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { 159 if (checker->IsTypeEqualityComparableTo(leftType, rightType) || 160 checker->IsTypeEqualityComparableTo(rightType, leftType)) { 161 return checker->GlobalBooleanType(); 162 } 163 164 checker->ThrowBinaryLikeError(operator_, leftType, rightType, Start()); 165 } 166 case lexer::TokenType::KEYW_INSTANCEOF: { 167 return checker->CheckInstanceofExpression(leftType, rightType, right_, this); 168 } 169 case lexer::TokenType::KEYW_IN: { 170 return checker->CheckInExpression(leftType, rightType, left_, right_, this); 171 } 172 case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { 173 return checker->CheckAndOperator(leftType, rightType, left_); 174 } 175 case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { 176 return checker->CheckOrOperator(leftType, rightType, left_); 177 } 178 case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: { 179 // TODO(Csaba Repasi): Implement checker for nullish coalescing 180 return checker->GlobalAnyType(); 181 } 182 case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: { 183 checker->CheckAssignmentOperator(operator_, left_, leftType, rightType); 184 return rightType; 185 } 186 default: { 187 UNREACHABLE(); 188 break; 189 } 190 } 191 192 return nullptr; 193} 194 195void BinaryExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder) 196{ 197 left_ = std::get<ir::AstNode *>(cb(left_))->AsExpression(); 198 right_ = std::get<ir::AstNode *>(cb(right_))->AsExpression(); 199} 200 201} // namespace panda::es2panda::ir 202