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 "enumPostCheckLowering.h"
17#include "checker/types/ets/etsEnumType.h"
18#include "checker/ETSchecker.h"
19#include "checker/types/type.h"
20#include "varbinder/ETSBinder.h"
21#include "varbinder/variable.h"
22
23namespace ark::es2panda::compiler {
24
25ir::CallExpression *EnumPostCheckLoweringPhase::CreateCall(
26    checker::ETSChecker *checker, ir::ClassDefinition *const classDef,
27    checker::ETSEnumType::Method (checker::ETSEnumType::*getMethod)() const, ir::Expression *argument)
28{
29    auto *classId = checker->AllocNode<ir::Identifier>(classDef->Ident()->Name(), checker->Allocator());
30    auto *methodId = checker->AllocNode<ir::Identifier>(
31        (argument->TsType()->AsETSEnumType()->*getMethod)().memberProxyType->Name(), checker->Allocator());
32    methodId->SetReference();
33    auto *callee = checker->AllocNode<ir::MemberExpression>(classId, methodId,
34                                                            ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
35
36    ArenaVector<ir::Expression *> callArguments(checker->Allocator()->Adapter());
37    callArguments.push_back(argument);
38    return checker->AllocNode<ir::CallExpression>(callee, std::move(callArguments), nullptr, false);
39}
40
41bool EnumPostCheckLoweringPhase::Perform(public_lib::Context *ctx, parser::Program *program)
42{
43    if (program->Extension() != ScriptExtension::ETS) {
44        return true;
45    }
46
47    for (auto &[_, extPrograms] : program->ExternalSources()) {
48        (void)_;
49        for (auto *extProg : extPrograms) {
50            Perform(ctx, extProg);
51        }
52    }
53    program->Ast()->TransformChildrenRecursivelyPostorder(
54        // clang-format off
55        [this, ctx](ir::AstNode *const node) -> ir::AstNode* {
56            if (node->HasAstNodeFlags(ir::AstNodeFlags::RECHECK)) {
57                if (node->IsExpression()) {
58                    node->AsExpression()->SetTsType(nullptr);  // force recheck
59                }
60                node->Check(ctx->checker->AsETSChecker());
61                node->RemoveAstNodeFlags(ir::AstNodeFlags::RECHECK);
62            }
63            if (node->HasAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF)) {
64                ASSERT(node->IsExpression());
65                auto expr = node->AsExpression();
66                auto parent = expr->Parent();
67                parent->AddAstNodeFlags(ir::AstNodeFlags::RECHECK);
68                ASSERT((node->AsExpression()->TsType()->IsETSEnumType()));
69                auto *enumIf = expr->TsType()->AsETSEnumType();
70                auto *callExpr = CreateCall(ctx->checker->AsETSChecker(), enumIf->GetDecl()->BoxedClass(),
71                                            &checker::ETSEnumType::ValueOfMethod, expr);
72                callExpr->SetParent(parent);
73                callExpr->Check(ctx->checker->AsETSChecker());
74                node->RemoveAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
75                return callExpr;
76            }
77            if (node->HasAstNodeFlags(ir::AstNodeFlags::GENERATE_GET_NAME)) {
78                ASSERT(node->IsMemberExpression());
79                auto memberExpr = node->AsMemberExpression();
80
81                auto *enumIf = memberExpr->Object()->TsType()->AsETSEnumType();
82                auto *callExpr = CreateCall(ctx->checker->AsETSChecker(), enumIf->GetDecl()->BoxedClass(),
83                                            &checker::ETSEnumType::GetNameMethod, memberExpr->Property());
84
85                callExpr->SetParent(node->Parent());
86                callExpr->Check(ctx->checker->AsETSChecker());
87                node->RemoveAstNodeFlags(ir::AstNodeFlags::GENERATE_GET_NAME);
88                return callExpr;
89            }
90            return node;
91        },
92        // clang-format on
93        Name());
94    return true;
95}
96
97}  // namespace ark::es2panda::compiler
98