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 "variableDeclaration.h"
17
18#include "macros.h"
19#include "varbinder/variable.h"
20#include "checker/TSchecker.h"
21#include "checker/ETSchecker.h"
22#include "compiler/core/ETSGen.h"
23#include "compiler/core/pandagen.h"
24#include "ir/astDump.h"
25#include "ir/srcDump.h"
26#include "ir/base/decorator.h"
27#include "ir/statements/variableDeclarator.h"
28
29namespace ark::es2panda::ir {
30void VariableDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName)
31{
32    for (auto *&it : decorators_) {
33        if (auto *transformedNode = cb(it); it != transformedNode) {
34            it->SetTransformedNode(transformationName, transformedNode);
35            it = transformedNode->AsDecorator();
36        }
37    }
38
39    for (auto *&it : declarators_) {
40        if (auto *transformedNode = cb(it); it != transformedNode) {
41            it->SetTransformedNode(transformationName, transformedNode);
42            it = transformedNode->AsVariableDeclarator();
43        }
44    }
45}
46
47void VariableDeclaration::Iterate(const NodeTraverser &cb) const
48{
49    for (auto *it : decorators_) {
50        cb(it);
51    }
52
53    for (auto *it : declarators_) {
54        cb(it);
55    }
56}
57
58void VariableDeclaration::Dump(ir::AstDumper *dumper) const
59{
60    const char *kind = nullptr;
61
62    switch (kind_) {
63        case VariableDeclarationKind::CONST: {
64            kind = "const";
65            break;
66        }
67        case VariableDeclarationKind::LET: {
68            kind = "let";
69            break;
70        }
71        case VariableDeclarationKind::VAR: {
72            kind = "var";
73            break;
74        }
75        default: {
76            UNREACHABLE();
77        }
78    }
79
80    dumper->Add({{"type", "VariableDeclaration"},
81                 {"declarations", declarators_},
82                 {"kind", kind},
83                 {"decorators", AstDumper::Optional(decorators_)},
84                 {"declare", AstDumper::Optional(declare_)}});
85}
86
87void VariableDeclaration::Dump(ir::SrcDumper *dumper) const
88{
89    switch (kind_) {
90        case VariableDeclarationKind::CONST:
91            dumper->Add("const ");
92            break;
93        case VariableDeclarationKind::LET:
94            dumper->Add("let ");
95            break;
96        case VariableDeclarationKind::VAR:
97            dumper->Add("var ");
98            break;
99        default:
100            UNREACHABLE();
101    }
102
103    for (auto declarator : declarators_) {
104        declarator->Dump(dumper);
105        if (declarator != declarators_.back()) {
106            dumper->Add(", ");
107        }
108    }
109
110    if ((parent_ != nullptr) &&
111        (parent_->IsBlockStatement() || parent_->IsBlockExpression() || parent_->IsSwitchCaseStatement())) {
112        dumper->Add(";");
113    }
114}
115
116VariableDeclaration::VariableDeclaration([[maybe_unused]] Tag const tag, VariableDeclaration const &other,
117                                         ArenaAllocator *const allocator)
118    : Statement(static_cast<Statement const &>(other)),
119      kind_(other.kind_),
120      decorators_(allocator->Adapter()),
121      declarators_(allocator->Adapter()),
122      declare_(other.declare_)
123{
124    for (auto const &d : other.decorators_) {
125        decorators_.emplace_back(d->Clone(allocator, nullptr));
126        decorators_.back()->SetParent(this);
127    }
128
129    for (auto const &d : other.declarators_) {
130        declarators_.emplace_back(d->Clone(allocator, nullptr)->AsVariableDeclarator());
131        declarators_.back()->SetParent(this);
132    }
133}
134
135VariableDeclaration *VariableDeclaration::Clone(ArenaAllocator *const allocator, AstNode *const parent)
136{
137    if (auto *const clone = allocator->New<VariableDeclaration>(Tag {}, *this, allocator); clone != nullptr) {
138        if (parent != nullptr) {
139            clone->SetParent(parent);
140        }
141        return clone;
142    }
143    throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR);
144}
145
146void VariableDeclaration::Compile(compiler::PandaGen *pg) const
147{
148    pg->GetAstCompiler()->Compile(this);
149}
150
151void VariableDeclaration::Compile(compiler::ETSGen *etsg) const
152{
153    etsg->GetAstCompiler()->Compile(this);
154}
155
156checker::Type *VariableDeclaration::Check(checker::TSChecker *checker)
157{
158    return checker->GetAnalyzer()->Check(this);
159}
160
161checker::Type *VariableDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker)
162{
163    return checker->GetAnalyzer()->Check(this);
164}
165}  // namespace ark::es2panda::ir
166