1/**
2 * Copyright (c) 2023-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 "structLowering.h"
17#include "checker/ETSchecker.h"
18#include "ir/base/classDefinition.h"
19#include "ir/base/classProperty.h"
20#include "ir/astNode.h"
21#include "ir/expression.h"
22#include "ir/opaqueTypeNode.h"
23#include "ir/expressions/identifier.h"
24#include "ir/statements/classDeclaration.h"
25#include "ir/ts/tsAsExpression.h"
26#include "type_helper.h"
27
28namespace ark::es2panda::compiler {
29
30const char *const STRUCT_CLASS_NAME = "CommonStruct0";
31
32ir::ETSTypeReference *CreateStructTypeReference(checker::ETSChecker *checker,
33                                                ir::ETSStructDeclaration *etsStrucDeclaration)
34{
35    auto *allocator = checker->Allocator();
36
37    ArenaVector<ir::TypeNode *> params(allocator->Adapter());
38
39    ir::TSTypeParameterInstantiation *typeParamSelfInst = nullptr;
40
41    if (etsStrucDeclaration->Definition()->TypeParams() != nullptr &&
42        !etsStrucDeclaration->Definition()->TypeParams()->Params().empty()) {
43        ArenaVector<ir::TypeNode *> selfParams(allocator->Adapter());
44        ir::ETSTypeReferencePart *referencePart = nullptr;
45
46        for (const auto &param : etsStrucDeclaration->Definition()->TypeParams()->Params()) {
47            auto *identRef = checker->AllocNode<ir::Identifier>(param->AsTSTypeParameter()->Name()->Name(), allocator);
48            identRef->AsIdentifier()->SetReference();
49
50            referencePart = checker->AllocNode<ir::ETSTypeReferencePart>(identRef, nullptr, nullptr);
51
52            auto *typeReference = checker->AllocNode<ir::ETSTypeReference>(referencePart);
53
54            selfParams.push_back(typeReference);
55        }
56
57        typeParamSelfInst = checker->AllocNode<ir::TSTypeParameterInstantiation>(std::move(selfParams));
58    }
59
60    auto *identSelfRef =
61        checker->AllocNode<ir::Identifier>(etsStrucDeclaration->Definition()->Ident()->Name(), allocator);
62    identSelfRef->AsIdentifier()->SetReference();
63
64    auto *referenceSelfPart = checker->AllocNode<ir::ETSTypeReferencePart>(identSelfRef, typeParamSelfInst, nullptr);
65
66    auto *selfTypeReference = checker->AllocNode<ir::ETSTypeReference>(referenceSelfPart);
67
68    params.push_back(selfTypeReference);
69
70    auto *typeParamInst = checker->AllocNode<ir::TSTypeParameterInstantiation>(std::move(params));
71
72    auto *identRef = checker->AllocNode<ir::Identifier>(util::StringView(STRUCT_CLASS_NAME), allocator);
73    identRef->AsIdentifier()->SetReference();
74    auto *referencePart = checker->AllocNode<ir::ETSTypeReferencePart>(identRef, typeParamInst, nullptr);
75
76    auto *typeReference = checker->AllocNode<ir::ETSTypeReference>(referencePart);
77
78    return typeReference;
79}
80
81using AstNodePtr = ir::AstNode *;
82
83bool StructLowering::Perform(public_lib::Context *ctx, parser::Program *program)
84{
85    for (auto &[_, ext_programs] : program->ExternalSources()) {
86        (void)_;
87        for (auto *extProg : ext_programs) {
88            Perform(ctx, extProg);
89        }
90    }
91
92    checker::ETSChecker *checker = ctx->checker->AsETSChecker();
93
94    program->Ast()->TransformChildrenRecursively(
95        [checker](ir::AstNode *ast) -> AstNodePtr {
96            if (ast->IsETSStructDeclaration()) {
97                auto *typeRef = CreateStructTypeReference(checker, ast->AsETSStructDeclaration());
98                ast->AsETSStructDeclaration()->Definition()->SetSuper(typeRef);
99                ast->AsETSStructDeclaration()->Definition()->AddModifier(ir::ModifierFlags::FINAL);
100            }
101
102            return ast;
103        },
104        Name());
105
106    return true;
107}
108
109}  // namespace ark::es2panda::compiler
110