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 "assignmentExpression.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include <compiler/base/lreference.h>
193af6ab5fSopenharmony_ci#include <compiler/core/pandagen.h>
203af6ab5fSopenharmony_ci#include <compiler/core/regScope.h>
213af6ab5fSopenharmony_ci#include <typescript/checker.h>
223af6ab5fSopenharmony_ci#include <typescript/core/destructuringContext.h>
233af6ab5fSopenharmony_ci#include <ir/astDump.h>
243af6ab5fSopenharmony_ci#include <ir/base/spreadElement.h>
253af6ab5fSopenharmony_ci#include <ir/expressions/arrayExpression.h>
263af6ab5fSopenharmony_ci#include <ir/expressions/objectExpression.h>
273af6ab5fSopenharmony_ci#include <ir/expressions/identifier.h>
283af6ab5fSopenharmony_ci
293af6ab5fSopenharmony_cinamespace panda::es2panda::ir {
303af6ab5fSopenharmony_ci
313af6ab5fSopenharmony_cibool AssignmentExpression::ConvertibleToAssignmentPattern(bool mustBePattern)
323af6ab5fSopenharmony_ci{
333af6ab5fSopenharmony_ci    bool convResult = true;
343af6ab5fSopenharmony_ci
353af6ab5fSopenharmony_ci    switch (left_->Type()) {
363af6ab5fSopenharmony_ci        case AstNodeType::ARRAY_EXPRESSION: {
373af6ab5fSopenharmony_ci            convResult = left_->AsArrayExpression()->ConvertibleToArrayPattern();
383af6ab5fSopenharmony_ci            break;
393af6ab5fSopenharmony_ci        }
403af6ab5fSopenharmony_ci        case AstNodeType::SPREAD_ELEMENT: {
413af6ab5fSopenharmony_ci            convResult = mustBePattern && left_->AsSpreadElement()->ConvertibleToRest(false);
423af6ab5fSopenharmony_ci            break;
433af6ab5fSopenharmony_ci        }
443af6ab5fSopenharmony_ci        case AstNodeType::OBJECT_EXPRESSION: {
453af6ab5fSopenharmony_ci            convResult = left_->AsObjectExpression()->ConvertibleToObjectPattern();
463af6ab5fSopenharmony_ci            break;
473af6ab5fSopenharmony_ci        }
483af6ab5fSopenharmony_ci        case AstNodeType::ASSIGNMENT_EXPRESSION: {
493af6ab5fSopenharmony_ci            convResult = left_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(mustBePattern);
503af6ab5fSopenharmony_ci            break;
513af6ab5fSopenharmony_ci        }
523af6ab5fSopenharmony_ci        case AstNodeType::META_PROPERTY_EXPRESSION:
533af6ab5fSopenharmony_ci        case AstNodeType::CHAIN_EXPRESSION: {
543af6ab5fSopenharmony_ci            convResult = false;
553af6ab5fSopenharmony_ci            break;
563af6ab5fSopenharmony_ci        }
573af6ab5fSopenharmony_ci        default: {
583af6ab5fSopenharmony_ci            break;
593af6ab5fSopenharmony_ci        }
603af6ab5fSopenharmony_ci    }
613af6ab5fSopenharmony_ci
623af6ab5fSopenharmony_ci    if (mustBePattern) {
633af6ab5fSopenharmony_ci        SetType(AstNodeType::ASSIGNMENT_PATTERN);
643af6ab5fSopenharmony_ci    }
653af6ab5fSopenharmony_ci
663af6ab5fSopenharmony_ci    if (!right_->IsAssignmentExpression()) {
673af6ab5fSopenharmony_ci        return convResult;
683af6ab5fSopenharmony_ci    }
693af6ab5fSopenharmony_ci
703af6ab5fSopenharmony_ci    switch (right_->Type()) {
713af6ab5fSopenharmony_ci        case AstNodeType::ARRAY_EXPRESSION: {
723af6ab5fSopenharmony_ci            convResult = right_->AsArrayExpression()->ConvertibleToArrayPattern();
733af6ab5fSopenharmony_ci            break;
743af6ab5fSopenharmony_ci        }
753af6ab5fSopenharmony_ci        case AstNodeType::CHAIN_EXPRESSION:
763af6ab5fSopenharmony_ci        case AstNodeType::SPREAD_ELEMENT: {
773af6ab5fSopenharmony_ci            convResult = false;
783af6ab5fSopenharmony_ci            break;
793af6ab5fSopenharmony_ci        }
803af6ab5fSopenharmony_ci        case AstNodeType::OBJECT_EXPRESSION: {
813af6ab5fSopenharmony_ci            convResult = right_->AsObjectExpression()->ConvertibleToObjectPattern();
823af6ab5fSopenharmony_ci            break;
833af6ab5fSopenharmony_ci        }
843af6ab5fSopenharmony_ci        case AstNodeType::ASSIGNMENT_EXPRESSION: {
853af6ab5fSopenharmony_ci            convResult = right_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(false);
863af6ab5fSopenharmony_ci            break;
873af6ab5fSopenharmony_ci        }
883af6ab5fSopenharmony_ci        default: {
893af6ab5fSopenharmony_ci            break;
903af6ab5fSopenharmony_ci        }
913af6ab5fSopenharmony_ci    }
923af6ab5fSopenharmony_ci
933af6ab5fSopenharmony_ci    return convResult;
943af6ab5fSopenharmony_ci}
953af6ab5fSopenharmony_ci
963af6ab5fSopenharmony_civoid AssignmentExpression::Iterate(const NodeTraverser &cb) const
973af6ab5fSopenharmony_ci{
983af6ab5fSopenharmony_ci    cb(left_);
993af6ab5fSopenharmony_ci    cb(right_);
1003af6ab5fSopenharmony_ci}
1013af6ab5fSopenharmony_ci
1023af6ab5fSopenharmony_civoid AssignmentExpression::Dump(ir::AstDumper *dumper) const
1033af6ab5fSopenharmony_ci{
1043af6ab5fSopenharmony_ci    if (type_ == AstNodeType::ASSIGNMENT_EXPRESSION) {
1053af6ab5fSopenharmony_ci        dumper->Add({{"type", "AssignmentExpression"}, {"operator", operator_}, {"left", left_}, {"right", right_}});
1063af6ab5fSopenharmony_ci    } else {
1073af6ab5fSopenharmony_ci        dumper->Add({{"type", "AssignmentPattern"}, {"left", left_}, {"right", right_}});
1083af6ab5fSopenharmony_ci    }
1093af6ab5fSopenharmony_ci}
1103af6ab5fSopenharmony_ci
1113af6ab5fSopenharmony_civoid AssignmentExpression::Compile(compiler::PandaGen *pg) const
1123af6ab5fSopenharmony_ci{
1133af6ab5fSopenharmony_ci    compiler::RegScope rs(pg);
1143af6ab5fSopenharmony_ci    compiler::LReference lref = compiler::LReference::CreateLRef(pg, left_, false);
1153af6ab5fSopenharmony_ci
1163af6ab5fSopenharmony_ci    if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND_EQUAL ||
1173af6ab5fSopenharmony_ci        operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR_EQUAL ||
1183af6ab5fSopenharmony_ci        operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_NULLISH_EQUAL) {
1193af6ab5fSopenharmony_ci        auto *skipRight = pg->AllocLabel();
1203af6ab5fSopenharmony_ci        auto *endLabel = pg->AllocLabel();
1213af6ab5fSopenharmony_ci        compiler::VReg lhsReg = pg->AllocReg();
1223af6ab5fSopenharmony_ci
1233af6ab5fSopenharmony_ci        lref.GetValue();
1243af6ab5fSopenharmony_ci        pg->StoreAccumulator(left_, lhsReg);
1253af6ab5fSopenharmony_ci        if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND_EQUAL) {
1263af6ab5fSopenharmony_ci            pg->BranchIfFalse(left_, skipRight);
1273af6ab5fSopenharmony_ci        } else if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR_EQUAL) {
1283af6ab5fSopenharmony_ci            pg->BranchIfTrue(left_, skipRight);
1293af6ab5fSopenharmony_ci        } else {
1303af6ab5fSopenharmony_ci            ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_NULLISH_EQUAL);
1313af6ab5fSopenharmony_ci            auto *nullish = pg->AllocLabel();
1323af6ab5fSopenharmony_ci            pg->BranchIfStrictNull(left_, nullish);
1333af6ab5fSopenharmony_ci            pg->LoadAccumulator(left_, lhsReg);
1343af6ab5fSopenharmony_ci            pg->BranchIfStrictNotUndefined(this, skipRight);
1353af6ab5fSopenharmony_ci            pg->SetLabel(left_, nullish);
1363af6ab5fSopenharmony_ci        }
1373af6ab5fSopenharmony_ci        // left = right
1383af6ab5fSopenharmony_ci        right_->Compile(pg);
1393af6ab5fSopenharmony_ci        lref.SetValue();
1403af6ab5fSopenharmony_ci        pg->Branch(this, endLabel);
1413af6ab5fSopenharmony_ci        // skip right part
1423af6ab5fSopenharmony_ci        pg->SetLabel(this, skipRight);
1433af6ab5fSopenharmony_ci        pg->LoadAccumulator(this, lhsReg);
1443af6ab5fSopenharmony_ci        pg->SetLabel(this, endLabel);
1453af6ab5fSopenharmony_ci        return;
1463af6ab5fSopenharmony_ci    } else if (operator_ != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
1473af6ab5fSopenharmony_ci        compiler::VReg lhsReg = pg->AllocReg();
1483af6ab5fSopenharmony_ci
1493af6ab5fSopenharmony_ci        lref.GetValue();
1503af6ab5fSopenharmony_ci        pg->StoreAccumulator(left_, lhsReg);
1513af6ab5fSopenharmony_ci        right_->Compile(pg);
1523af6ab5fSopenharmony_ci        pg->Binary(this, operator_, lhsReg);
1533af6ab5fSopenharmony_ci    } else {
1543af6ab5fSopenharmony_ci        right_->Compile(pg);
1553af6ab5fSopenharmony_ci    }
1563af6ab5fSopenharmony_ci
1573af6ab5fSopenharmony_ci    lref.SetValue();
1583af6ab5fSopenharmony_ci}
1593af6ab5fSopenharmony_ci
1603af6ab5fSopenharmony_civoid AssignmentExpression::CompilePattern(compiler::PandaGen *pg) const
1613af6ab5fSopenharmony_ci{
1623af6ab5fSopenharmony_ci    compiler::RegScope rs(pg);
1633af6ab5fSopenharmony_ci    compiler::LReference lref = compiler::LReference::CreateLRef(pg, left_, false);
1643af6ab5fSopenharmony_ci    right_->Compile(pg);
1653af6ab5fSopenharmony_ci    lref.SetValue();
1663af6ab5fSopenharmony_ci}
1673af6ab5fSopenharmony_ci
1683af6ab5fSopenharmony_cichecker::Type *AssignmentExpression::Check(checker::Checker *checker) const
1693af6ab5fSopenharmony_ci{
1703af6ab5fSopenharmony_ci    if (left_->IsArrayPattern()) {
1713af6ab5fSopenharmony_ci        auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
1723af6ab5fSopenharmony_ci        auto destructuringContext = checker::ArrayDestructuringContext(checker, left_, true, true, nullptr, right_);
1733af6ab5fSopenharmony_ci        destructuringContext.Start();
1743af6ab5fSopenharmony_ci        return destructuringContext.InferedType();
1753af6ab5fSopenharmony_ci    }
1763af6ab5fSopenharmony_ci
1773af6ab5fSopenharmony_ci    if (left_->IsObjectPattern()) {
1783af6ab5fSopenharmony_ci        auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
1793af6ab5fSopenharmony_ci        auto destructuringContext = checker::ObjectDestructuringContext(checker, left_, true, true, nullptr, right_);
1803af6ab5fSopenharmony_ci        destructuringContext.Start();
1813af6ab5fSopenharmony_ci        return destructuringContext.InferedType();
1823af6ab5fSopenharmony_ci    }
1833af6ab5fSopenharmony_ci
1843af6ab5fSopenharmony_ci    if (left_->IsIdentifier() && left_->AsIdentifier()->Variable() &&
1853af6ab5fSopenharmony_ci        left_->AsIdentifier()->Variable()->Declaration()->IsConstDecl()) {
1863af6ab5fSopenharmony_ci        checker->ThrowTypeError({"Cannot assign to ", left_->AsIdentifier()->Name(), " because it is a constant."},
1873af6ab5fSopenharmony_ci                                left_->Start());
1883af6ab5fSopenharmony_ci    }
1893af6ab5fSopenharmony_ci
1903af6ab5fSopenharmony_ci    auto *leftType = left_->Check(checker);
1913af6ab5fSopenharmony_ci
1923af6ab5fSopenharmony_ci    if (leftType->HasTypeFlag(checker::TypeFlag::READONLY)) {
1933af6ab5fSopenharmony_ci        checker->ThrowTypeError("Cannot assign to this property because it is readonly.", left_->Start());
1943af6ab5fSopenharmony_ci    }
1953af6ab5fSopenharmony_ci
1963af6ab5fSopenharmony_ci    if (operator_ == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
1973af6ab5fSopenharmony_ci        checker->ElaborateElementwise(leftType, right_, left_->Start());
1983af6ab5fSopenharmony_ci        return checker->CheckTypeCached(right_);
1993af6ab5fSopenharmony_ci    }
2003af6ab5fSopenharmony_ci
2013af6ab5fSopenharmony_ci    auto *rightType = right_->Check(checker);
2023af6ab5fSopenharmony_ci
2033af6ab5fSopenharmony_ci    switch (operator_) {
2043af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL:
2053af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL:
2063af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
2073af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MOD_EQUAL:
2083af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL:
2093af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL:
2103af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL:
2113af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL:
2123af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL:
2133af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL:
2143af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: {
2153af6ab5fSopenharmony_ci            return checker->CheckBinaryOperator(leftType, rightType, left_, right_, this, operator_);
2163af6ab5fSopenharmony_ci        }
2173af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
2183af6ab5fSopenharmony_ci            return checker->CheckPlusOperator(leftType, rightType, left_, right_, this, operator_);
2193af6ab5fSopenharmony_ci        }
2203af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
2213af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
2223af6ab5fSopenharmony_ci            return checker->CheckCompareOperator(leftType, rightType, left_, right_, this, operator_);
2233af6ab5fSopenharmony_ci        }
2243af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
2253af6ab5fSopenharmony_ci            checker->CheckAssignmentOperator(operator_, left_, leftType, rightType);
2263af6ab5fSopenharmony_ci            return rightType;
2273af6ab5fSopenharmony_ci        }
2283af6ab5fSopenharmony_ci        default: {
2293af6ab5fSopenharmony_ci            UNREACHABLE();
2303af6ab5fSopenharmony_ci            break;
2313af6ab5fSopenharmony_ci        }
2323af6ab5fSopenharmony_ci    }
2333af6ab5fSopenharmony_ci
2343af6ab5fSopenharmony_ci    return nullptr;
2353af6ab5fSopenharmony_ci}
2363af6ab5fSopenharmony_ci
2373af6ab5fSopenharmony_civoid AssignmentExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
2383af6ab5fSopenharmony_ci{
2393af6ab5fSopenharmony_ci    left_ = std::get<ir::AstNode *>(cb(left_))->AsExpression();
2403af6ab5fSopenharmony_ci    right_ = std::get<ir::AstNode *>(cb(right_))->AsExpression();
2413af6ab5fSopenharmony_ci}
2423af6ab5fSopenharmony_ci
2433af6ab5fSopenharmony_ci}  // namespace panda::es2panda::ir
244