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 "spreadElement.h"
17#include "es2panda.h"
18
19#include "checker/TSchecker.h"
20#include "compiler/core/pandagen.h"
21#include "compiler/core/ETSGen.h"
22#include "ir/astDump.h"
23#include "ir/srcDump.h"
24#include "ir/base/decorator.h"
25#include "ir/typeNode.h"
26#include "ir/expressions/arrayExpression.h"
27#include "ir/expressions/objectExpression.h"
28
29namespace ark::es2panda::ir {
30SpreadElement::SpreadElement([[maybe_unused]] Tag const tag, SpreadElement const &other,
31                             ArenaAllocator *const allocator)
32    : AnnotatedExpression(static_cast<AnnotatedExpression const &>(other), allocator), decorators_(allocator->Adapter())
33{
34    optional_ = other.optional_;
35
36    if (other.argument_ != nullptr) {
37        argument_ = other.argument_->Clone(allocator, this)->AsExpression();
38    }
39
40    for (auto *decorator : other.decorators_) {
41        decorators_.emplace_back(decorator->Clone(allocator, this));
42    }
43}
44
45SpreadElement *SpreadElement::Clone(ArenaAllocator *const allocator, AstNode *const parent)
46{
47    if (auto *const clone = allocator->New<SpreadElement>(Tag {}, *this, allocator); clone != nullptr) {
48        if (parent != nullptr) {
49            clone->SetParent(parent);
50        }
51        return clone;
52    }
53    throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR);
54}
55
56ValidationInfo SpreadElement::ValidateExpression()
57{
58    ValidationInfo info;
59
60    switch (argument_->Type()) {
61        case AstNodeType::OBJECT_EXPRESSION: {
62            info = argument_->AsObjectExpression()->ValidateExpression();
63            break;
64        }
65        case AstNodeType::ARRAY_EXPRESSION: {
66            info = argument_->AsArrayExpression()->ValidateExpression();
67            break;
68        }
69        default: {
70            break;
71        }
72    }
73
74    return info;
75}
76
77bool SpreadElement::ConvertibleToRest(bool isDeclaration, bool allowPattern)
78{
79    bool convResult = true;
80
81    switch (argument_->Type()) {
82        case AstNodeType::ARRAY_EXPRESSION: {
83            convResult = allowPattern && argument_->AsArrayExpression()->ConvertibleToArrayPattern();
84            break;
85        }
86        case AstNodeType::OBJECT_EXPRESSION: {
87            convResult = allowPattern && argument_->AsObjectExpression()->ConvertibleToObjectPattern();
88            break;
89        }
90        case AstNodeType::META_PROPERTY_EXPRESSION:
91        case AstNodeType::CHAIN_EXPRESSION:
92        case AstNodeType::ASSIGNMENT_EXPRESSION: {
93            convResult = false;
94            break;
95        }
96        case AstNodeType::MEMBER_EXPRESSION: {
97            convResult = !isDeclaration;
98            break;
99        }
100        default: {
101            break;
102        }
103    }
104
105    SetType(AstNodeType::REST_ELEMENT);
106    return convResult;
107}
108
109void SpreadElement::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)
110{
111    for (auto *&it : decorators_) {
112        if (auto *transformedNode = cb(it); it != transformedNode) {
113            it->SetTransformedNode(transformationName, transformedNode);
114            it = transformedNode->AsDecorator();
115        }
116    }
117
118    if (auto *transformedNode = cb(argument_); argument_ != transformedNode) {
119        argument_->SetTransformedNode(transformationName, transformedNode);
120        argument_ = transformedNode->AsExpression();
121    }
122
123    if (auto *const typeAnnotation = TypeAnnotation(); typeAnnotation != nullptr) {
124        if (auto *transformedNode = cb(typeAnnotation); typeAnnotation != transformedNode) {
125            typeAnnotation->SetTransformedNode(transformationName, transformedNode);
126            SetTsTypeAnnotation(static_cast<TypeNode *>(transformedNode));
127        }
128    }
129}
130
131void SpreadElement::Iterate(const NodeTraverser &cb) const
132{
133    for (auto *it : decorators_) {
134        cb(it);
135    }
136
137    cb(argument_);
138
139    if (TypeAnnotation() != nullptr) {
140        cb(TypeAnnotation());
141    }
142}
143
144void SpreadElement::Dump(ir::AstDumper *dumper) const
145{
146    dumper->Add({{"type", (type_ == AstNodeType::SPREAD_ELEMENT) ? "SpreadElement" : "RestElement"},
147                 {"decorators", AstDumper::Optional(decorators_)},
148                 {"argument", argument_},
149                 {"typeAnnotation", AstDumper::Optional(TypeAnnotation())}});
150}
151
152void SpreadElement::Dump(ir::SrcDumper *dumper) const
153{
154    dumper->Add("...");
155    argument_->Dump(dumper);
156    auto type = TypeAnnotation();
157    if (type != nullptr) {
158        dumper->Add(": ");
159        type->Dump(dumper);
160    }
161}
162
163void SpreadElement::Compile([[maybe_unused]] compiler::PandaGen *pg) const
164{
165    pg->GetAstCompiler()->Compile(this);
166}
167void SpreadElement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const
168{
169    etsg->GetAstCompiler()->Compile(this);
170}
171
172checker::Type *SpreadElement::Check([[maybe_unused]] checker::TSChecker *checker)
173{
174    return checker->GetAnalyzer()->Check(this);
175}
176
177checker::Type *SpreadElement::Check([[maybe_unused]] checker::ETSChecker *checker)
178{
179    return checker->GetAnalyzer()->Check(this);
180}
181}  // namespace ark::es2panda::ir
182