1/**
2 * Copyright (c) 2021-2024 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/ETSGen.h"
21#include "compiler/core/regScope.h"
22#include "ir/astDump.h"
23#include "ir/srcDump.h"
24#include "ir/base/spreadElement.h"
25#include "ir/expressions/arrayExpression.h"
26#include "ir/expressions/objectExpression.h"
27
28#include "checker/TSchecker.h"
29#include "checker/ts/destructuringContext.h"
30#include "checker/ets/typeRelationContext.h"
31
32namespace ark::es2panda::ir {
33
34bool AssignmentExpression::ConvertibleToAssignmentPatternLeft(bool mustBePattern)
35{
36    switch (left_->Type()) {
37        case AstNodeType::ARRAY_EXPRESSION: {
38            return left_->AsArrayExpression()->ConvertibleToArrayPattern();
39        }
40        case AstNodeType::SPREAD_ELEMENT: {
41            return mustBePattern && left_->AsSpreadElement()->ConvertibleToRest(false);
42        }
43        case AstNodeType::OBJECT_EXPRESSION: {
44            return left_->AsObjectExpression()->ConvertibleToObjectPattern();
45        }
46        case AstNodeType::ASSIGNMENT_EXPRESSION: {
47            return left_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(mustBePattern);
48        }
49        case AstNodeType::META_PROPERTY_EXPRESSION:
50        case AstNodeType::CHAIN_EXPRESSION: {
51            return false;
52        }
53        default: {
54            return true;
55        }
56    }
57}
58
59bool AssignmentExpression::ConvertibleToAssignmentPatternRight()
60{
61    switch (right_->Type()) {
62        case AstNodeType::ARRAY_EXPRESSION: {
63            return right_->AsArrayExpression()->ConvertibleToArrayPattern();
64        }
65        case AstNodeType::CHAIN_EXPRESSION:
66        case AstNodeType::SPREAD_ELEMENT: {
67            return false;
68        }
69        case AstNodeType::OBJECT_EXPRESSION: {
70            return right_->AsObjectExpression()->ConvertibleToObjectPattern();
71        }
72        case AstNodeType::ASSIGNMENT_EXPRESSION: {
73            return right_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(false);
74        }
75        default: {
76            return true;
77        }
78    }
79}
80
81bool AssignmentExpression::ConvertibleToAssignmentPattern(bool mustBePattern)
82{
83    bool convResult = ConvertibleToAssignmentPatternLeft(mustBePattern);
84    if (mustBePattern) {
85        SetType(AstNodeType::ASSIGNMENT_PATTERN);
86    }
87
88    if (!right_->IsAssignmentExpression()) {
89        return convResult;
90    }
91    return ConvertibleToAssignmentPatternRight();
92}
93
94void AssignmentExpression::TransformChildren(const NodeTransformer &cb, std::string_view transformationName)
95{
96    if (auto *transformedNode = cb(left_); left_ != transformedNode) {
97        left_->SetTransformedNode(transformationName, transformedNode);
98        left_ = transformedNode->AsExpression();
99    }
100
101    if (auto *transformedNode = cb(right_); right_ != transformedNode) {
102        right_->SetTransformedNode(transformationName, transformedNode);
103        right_ = transformedNode->AsExpression();
104    }
105}
106
107void AssignmentExpression::Iterate(const NodeTraverser &cb) const
108{
109    cb(left_);
110    cb(right_);
111}
112
113void AssignmentExpression::Dump(ir::AstDumper *dumper) const
114{
115    if (type_ == AstNodeType::ASSIGNMENT_EXPRESSION) {
116        dumper->Add({{"type", "AssignmentExpression"}, {"operator", operator_}, {"left", left_}, {"right", right_}});
117    } else {
118        dumper->Add({{"type", "AssignmentPattern"}, {"left", left_}, {"right", right_}});
119    }
120}
121
122void AssignmentExpression::Dump(ir::SrcDumper *dumper) const
123{
124    ASSERT(left_);
125    left_->Dump(dumper);
126    dumper->Add(" ");
127    dumper->Add(TokenToString(operator_));
128    dumper->Add(" ");
129    ASSERT(right_);
130    right_->Dump(dumper);
131}
132
133void AssignmentExpression::Compile(compiler::PandaGen *pg) const
134{
135    pg->GetAstCompiler()->Compile(this);
136}
137
138void AssignmentExpression::Compile(compiler::ETSGen *etsg) const
139{
140    etsg->GetAstCompiler()->Compile(this);
141}
142
143void AssignmentExpression::CompilePattern(compiler::PandaGen *pg) const
144{
145    compiler::RegScope rs(pg);
146    auto lref = compiler::JSLReference::Create(pg, left_, false);
147    right_->Compile(pg);
148    lref.SetValue();
149}
150
151checker::Type *AssignmentExpression::Check(checker::TSChecker *checker)
152{
153    return checker->GetAnalyzer()->Check(this);
154}
155
156checker::Type *AssignmentExpression::Check([[maybe_unused]] checker::ETSChecker *checker)
157{
158    return checker->GetAnalyzer()->Check(this);
159}
160
161AssignmentExpression::AssignmentExpression([[maybe_unused]] Tag const tag, AssignmentExpression const &other,
162                                           Expression *const left, Expression *const right)
163    : AssignmentExpression(other)
164{
165    left_ = left;
166    if (left_ != nullptr) {
167        left_->SetParent(this);
168    }
169
170    right_ = right;
171    if (right_ != nullptr) {
172        right_->SetParent(this);
173    }
174}
175
176AssignmentExpression *AssignmentExpression::Clone(ArenaAllocator *const allocator, AstNode *const parent)
177{
178    auto *const left = left_ != nullptr ? left_->Clone(allocator, nullptr)->AsExpression() : nullptr;
179    auto *const right = right_ != nullptr ? right_->Clone(allocator, nullptr)->AsExpression() : nullptr;
180
181    if (auto *const clone = allocator->New<AssignmentExpression>(Tag {}, *this, left, right); clone != nullptr) {
182        if (parent != nullptr) {
183            clone->SetParent(parent);
184        }
185
186        clone->SetRange(Range());
187        return clone;
188    }
189
190    throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR);
191}
192}  // namespace ark::es2panda::ir
193