13af6ab5fSopenharmony_ci/**
23af6ab5fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#include "binaryExpression.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include <binder/variable.h>
193af6ab5fSopenharmony_ci#include <compiler/core/pandagen.h>
203af6ab5fSopenharmony_ci#include <compiler/core/regScope.h>
213af6ab5fSopenharmony_ci#include <typescript/checker.h>
223af6ab5fSopenharmony_ci#include <ir/astDump.h>
233af6ab5fSopenharmony_ci#include <ir/base/classDefinition.h>
243af6ab5fSopenharmony_ci#include <ir/expressions/privateIdentifier.h>
253af6ab5fSopenharmony_ci#include <lexer/token/tokenType.h>
263af6ab5fSopenharmony_ci
273af6ab5fSopenharmony_cinamespace panda::es2panda::ir {
283af6ab5fSopenharmony_ci
293af6ab5fSopenharmony_civoid BinaryExpression::Iterate(const NodeTraverser &cb) const
303af6ab5fSopenharmony_ci{
313af6ab5fSopenharmony_ci    cb(left_);
323af6ab5fSopenharmony_ci    cb(right_);
333af6ab5fSopenharmony_ci}
343af6ab5fSopenharmony_ci
353af6ab5fSopenharmony_civoid BinaryExpression::Dump(ir::AstDumper *dumper) const
363af6ab5fSopenharmony_ci{
373af6ab5fSopenharmony_ci    dumper->Add({{"type", IsLogical() ? "LogicalExpression" : "BinaryExpression"},
383af6ab5fSopenharmony_ci                 {"operator", operator_},
393af6ab5fSopenharmony_ci                 {"left", left_},
403af6ab5fSopenharmony_ci                 {"right", right_}});
413af6ab5fSopenharmony_ci}
423af6ab5fSopenharmony_ci
433af6ab5fSopenharmony_civoid BinaryExpression::CompileLogical(compiler::PandaGen *pg) const
443af6ab5fSopenharmony_ci{
453af6ab5fSopenharmony_ci    compiler::RegScope rs(pg);
463af6ab5fSopenharmony_ci    compiler::VReg lhs = pg->AllocReg();
473af6ab5fSopenharmony_ci
483af6ab5fSopenharmony_ci    ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND ||
493af6ab5fSopenharmony_ci           operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR ||
503af6ab5fSopenharmony_ci           operator_ == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING);
513af6ab5fSopenharmony_ci    auto *skipRight = pg->AllocLabel();
523af6ab5fSopenharmony_ci    auto *endLabel = pg->AllocLabel();
533af6ab5fSopenharmony_ci
543af6ab5fSopenharmony_ci    // left -> acc -> lhs -> toboolean -> acc -> bool_lhs
553af6ab5fSopenharmony_ci    left_->Compile(pg);
563af6ab5fSopenharmony_ci    pg->StoreAccumulator(this, lhs);
573af6ab5fSopenharmony_ci
583af6ab5fSopenharmony_ci    if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) {
593af6ab5fSopenharmony_ci        pg->BranchIfFalse(this, skipRight);
603af6ab5fSopenharmony_ci    } else if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR) {
613af6ab5fSopenharmony_ci        pg->BranchIfTrue(this, skipRight);
623af6ab5fSopenharmony_ci    } else {
633af6ab5fSopenharmony_ci        ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING);
643af6ab5fSopenharmony_ci        auto *nullish = pg->AllocLabel();
653af6ab5fSopenharmony_ci        // if lhs === null
663af6ab5fSopenharmony_ci        pg->BranchIfStrictNull(this, nullish);
673af6ab5fSopenharmony_ci        pg->LoadAccumulator(this, lhs);
683af6ab5fSopenharmony_ci        // if lhs === undefined
693af6ab5fSopenharmony_ci        pg->BranchIfStrictNotUndefined(this, skipRight);
703af6ab5fSopenharmony_ci        pg->SetLabel(this, nullish);
713af6ab5fSopenharmony_ci    }
723af6ab5fSopenharmony_ci
733af6ab5fSopenharmony_ci    // left is true/false(and/or) then right -> acc
743af6ab5fSopenharmony_ci    right_->Compile(pg);
753af6ab5fSopenharmony_ci    pg->Branch(this, endLabel);
763af6ab5fSopenharmony_ci
773af6ab5fSopenharmony_ci    // left is false/true(and/or) then lhs -> acc
783af6ab5fSopenharmony_ci    pg->SetLabel(this, skipRight);
793af6ab5fSopenharmony_ci    pg->LoadAccumulator(this, lhs);
803af6ab5fSopenharmony_ci    pg->SetLabel(this, endLabel);
813af6ab5fSopenharmony_ci}
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_civoid BinaryExpression::CompilePrivateIn(compiler::PandaGen *pg) const
843af6ab5fSopenharmony_ci{
853af6ab5fSopenharmony_ci    ASSERT(operator_ == lexer::TokenType::KEYW_IN);
863af6ab5fSopenharmony_ci    auto name = left_->AsPrivateIdentifier()->Name();
873af6ab5fSopenharmony_ci    auto result = pg->Scope()->FindPrivateName(name);
883af6ab5fSopenharmony_ci
893af6ab5fSopenharmony_ci    right_->Compile(pg);
903af6ab5fSopenharmony_ci    if (!result.result.isMethod) {
913af6ab5fSopenharmony_ci        pg->TestIn(this, result.lexLevel, result.result.slot);
923af6ab5fSopenharmony_ci        return;
933af6ab5fSopenharmony_ci    }
943af6ab5fSopenharmony_ci    // Instance private method check symbol("#method")
953af6ab5fSopenharmony_ci    if (!result.result.isStatic) {
963af6ab5fSopenharmony_ci        pg->TestIn(this, result.lexLevel, result.result.validateMethodSlot);
973af6ab5fSopenharmony_ci        return;
983af6ab5fSopenharmony_ci    }
993af6ab5fSopenharmony_ci    // Static private method check whether equals the class object
1003af6ab5fSopenharmony_ci    compiler::RegScope rs(pg);
1013af6ab5fSopenharmony_ci    compiler::VReg rhs = pg->AllocReg();
1023af6ab5fSopenharmony_ci    pg->StoreAccumulator(right_, rhs);
1033af6ab5fSopenharmony_ci    pg->LoadLexicalVar(this, result.lexLevel, result.result.validateMethodSlot);
1043af6ab5fSopenharmony_ci    pg->Equal(this, rhs);
1053af6ab5fSopenharmony_ci}
1063af6ab5fSopenharmony_ci
1073af6ab5fSopenharmony_civoid BinaryExpression::Compile(compiler::PandaGen *pg) const
1083af6ab5fSopenharmony_ci{
1093af6ab5fSopenharmony_ci    if (left_->IsPrivateIdentifier()) {
1103af6ab5fSopenharmony_ci        CompilePrivateIn(pg);
1113af6ab5fSopenharmony_ci        return;
1123af6ab5fSopenharmony_ci    }
1133af6ab5fSopenharmony_ci
1143af6ab5fSopenharmony_ci    if (IsLogical()) {
1153af6ab5fSopenharmony_ci        CompileLogical(pg);
1163af6ab5fSopenharmony_ci        return;
1173af6ab5fSopenharmony_ci    }
1183af6ab5fSopenharmony_ci
1193af6ab5fSopenharmony_ci    compiler::RegScope rs(pg);
1203af6ab5fSopenharmony_ci    compiler::VReg lhs = pg->AllocReg();
1213af6ab5fSopenharmony_ci
1223af6ab5fSopenharmony_ci    left_->Compile(pg);
1233af6ab5fSopenharmony_ci    pg->StoreAccumulator(right_, lhs);
1243af6ab5fSopenharmony_ci    right_->Compile(pg);
1253af6ab5fSopenharmony_ci
1263af6ab5fSopenharmony_ci    pg->Binary(right_, operator_, lhs);
1273af6ab5fSopenharmony_ci}
1283af6ab5fSopenharmony_ci
1293af6ab5fSopenharmony_cichecker::Type *BinaryExpression::Check(checker::Checker *checker) const
1303af6ab5fSopenharmony_ci{
1313af6ab5fSopenharmony_ci    auto *leftType = left_->Check(checker);
1323af6ab5fSopenharmony_ci    auto *rightType = right_->Check(checker);
1333af6ab5fSopenharmony_ci
1343af6ab5fSopenharmony_ci    switch (operator_) {
1353af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MULTIPLY:
1363af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EXPONENTIATION:
1373af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_DIVIDE:
1383af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MOD:
1393af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS:
1403af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
1413af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
1423af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT:
1433af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_AND:
1443af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_XOR:
1453af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_OR: {
1463af6ab5fSopenharmony_ci            return checker->CheckBinaryOperator(leftType, rightType, left_, right_, this, operator_);
1473af6ab5fSopenharmony_ci        }
1483af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS: {
1493af6ab5fSopenharmony_ci            return checker->CheckPlusOperator(leftType, rightType, left_, right_, this, operator_);
1503af6ab5fSopenharmony_ci        }
1513af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LESS_THAN:
1523af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
1533af6ab5fSopenharmony_ci            return checker->CheckCompareOperator(leftType, rightType, left_, right_, this, operator_);
1543af6ab5fSopenharmony_ci        }
1553af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EQUAL:
1563af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
1573af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
1583af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
1593af6ab5fSopenharmony_ci            if (checker->IsTypeEqualityComparableTo(leftType, rightType) ||
1603af6ab5fSopenharmony_ci                checker->IsTypeEqualityComparableTo(rightType, leftType)) {
1613af6ab5fSopenharmony_ci                return checker->GlobalBooleanType();
1623af6ab5fSopenharmony_ci            }
1633af6ab5fSopenharmony_ci
1643af6ab5fSopenharmony_ci            checker->ThrowBinaryLikeError(operator_, leftType, rightType, Start());
1653af6ab5fSopenharmony_ci        }
1663af6ab5fSopenharmony_ci        case lexer::TokenType::KEYW_INSTANCEOF: {
1673af6ab5fSopenharmony_ci            return checker->CheckInstanceofExpression(leftType, rightType, right_, this);
1683af6ab5fSopenharmony_ci        }
1693af6ab5fSopenharmony_ci        case lexer::TokenType::KEYW_IN: {
1703af6ab5fSopenharmony_ci            return checker->CheckInExpression(leftType, rightType, left_, right_, this);
1713af6ab5fSopenharmony_ci        }
1723af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
1733af6ab5fSopenharmony_ci            return checker->CheckAndOperator(leftType, rightType, left_);
1743af6ab5fSopenharmony_ci        }
1753af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
1763af6ab5fSopenharmony_ci            return checker->CheckOrOperator(leftType, rightType, left_);
1773af6ab5fSopenharmony_ci        }
1783af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: {
1793af6ab5fSopenharmony_ci            // TODO(Csaba Repasi): Implement checker for nullish coalescing
1803af6ab5fSopenharmony_ci            return checker->GlobalAnyType();
1813af6ab5fSopenharmony_ci        }
1823af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
1833af6ab5fSopenharmony_ci            checker->CheckAssignmentOperator(operator_, left_, leftType, rightType);
1843af6ab5fSopenharmony_ci            return rightType;
1853af6ab5fSopenharmony_ci        }
1863af6ab5fSopenharmony_ci        default: {
1873af6ab5fSopenharmony_ci            UNREACHABLE();
1883af6ab5fSopenharmony_ci            break;
1893af6ab5fSopenharmony_ci        }
1903af6ab5fSopenharmony_ci    }
1913af6ab5fSopenharmony_ci
1923af6ab5fSopenharmony_ci    return nullptr;
1933af6ab5fSopenharmony_ci}
1943af6ab5fSopenharmony_ci
1953af6ab5fSopenharmony_civoid BinaryExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
1963af6ab5fSopenharmony_ci{
1973af6ab5fSopenharmony_ci    left_ = std::get<ir::AstNode *>(cb(left_))->AsExpression();
1983af6ab5fSopenharmony_ci    right_ = std::get<ir::AstNode *>(cb(right_))->AsExpression();
1993af6ab5fSopenharmony_ci}
2003af6ab5fSopenharmony_ci
2013af6ab5fSopenharmony_ci}  // namespace panda::es2panda::ir
202