13af6ab5fSopenharmony_ci/**
23af6ab5fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#include "tsEnumDeclaration.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include <binder/scope.h>
193af6ab5fSopenharmony_ci#include <util/helpers.h>
203af6ab5fSopenharmony_ci#include <ir/astDump.h>
213af6ab5fSopenharmony_ci#include <ir/expressions/identifier.h>
223af6ab5fSopenharmony_ci#include <ir/expressions/memberExpression.h>
233af6ab5fSopenharmony_ci#include <ir/expressions/unaryExpression.h>
243af6ab5fSopenharmony_ci#include <ir/expressions/binaryExpression.h>
253af6ab5fSopenharmony_ci#include <ir/expressions/templateLiteral.h>
263af6ab5fSopenharmony_ci#include <ir/expressions/literals/stringLiteral.h>
273af6ab5fSopenharmony_ci#include <ir/expressions/literals/numberLiteral.h>
283af6ab5fSopenharmony_ci#include <ir/ts/tsEnumMember.h>
293af6ab5fSopenharmony_ci#include <typescript/checker.h>
303af6ab5fSopenharmony_ci
313af6ab5fSopenharmony_cinamespace panda::es2panda::ir {
323af6ab5fSopenharmony_ci
333af6ab5fSopenharmony_civoid TSEnumDeclaration::Iterate(const NodeTraverser &cb) const
343af6ab5fSopenharmony_ci{
353af6ab5fSopenharmony_ci    cb(key_);
363af6ab5fSopenharmony_ci
373af6ab5fSopenharmony_ci    for (auto *it : members_) {
383af6ab5fSopenharmony_ci        cb(it);
393af6ab5fSopenharmony_ci    }
403af6ab5fSopenharmony_ci}
413af6ab5fSopenharmony_ci
423af6ab5fSopenharmony_civoid TSEnumDeclaration::Dump(ir::AstDumper *dumper) const
433af6ab5fSopenharmony_ci{
443af6ab5fSopenharmony_ci    dumper->Add({{"type", "TSEnumDeclaration"}, {"id", key_}, {"members", members_}, {"const", isConst_}});
453af6ab5fSopenharmony_ci}
463af6ab5fSopenharmony_ci
473af6ab5fSopenharmony_civoid TSEnumDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {}
483af6ab5fSopenharmony_ci
493af6ab5fSopenharmony_ciint32_t ToInt(double num)
503af6ab5fSopenharmony_ci{
513af6ab5fSopenharmony_ci    if (num >= std::numeric_limits<int32_t>::min() && num <= std::numeric_limits<int32_t>::max()) {
523af6ab5fSopenharmony_ci        return static_cast<int32_t>(num);
533af6ab5fSopenharmony_ci    }
543af6ab5fSopenharmony_ci
553af6ab5fSopenharmony_ci    // TODO(aszilagyi): Perform ECMA defined toInt conversion
563af6ab5fSopenharmony_ci
573af6ab5fSopenharmony_ci    return 0;
583af6ab5fSopenharmony_ci}
593af6ab5fSopenharmony_ci
603af6ab5fSopenharmony_ciuint32_t ToUInt(double num)
613af6ab5fSopenharmony_ci{
623af6ab5fSopenharmony_ci    if (num >= std::numeric_limits<uint32_t>::min() && num <= std::numeric_limits<uint32_t>::max()) {
633af6ab5fSopenharmony_ci        return static_cast<int32_t>(num);
643af6ab5fSopenharmony_ci    }
653af6ab5fSopenharmony_ci
663af6ab5fSopenharmony_ci    // TODO(aszilagyi): Perform ECMA defined toInt conversion
673af6ab5fSopenharmony_ci
683af6ab5fSopenharmony_ci    return 0;
693af6ab5fSopenharmony_ci}
703af6ab5fSopenharmony_ci
713af6ab5fSopenharmony_cibinder::EnumMemberResult EvaluateIdentifier(checker::Checker *checker, binder::EnumVariable *enumVar,
723af6ab5fSopenharmony_ci                                            const ir::Identifier *expr)
733af6ab5fSopenharmony_ci{
743af6ab5fSopenharmony_ci    if (expr->Name() == "NaN") {
753af6ab5fSopenharmony_ci        return std::nan("");
763af6ab5fSopenharmony_ci    }
773af6ab5fSopenharmony_ci    if (expr->Name() == "Infinity") {
783af6ab5fSopenharmony_ci        return std::numeric_limits<double>::infinity();
793af6ab5fSopenharmony_ci    }
803af6ab5fSopenharmony_ci
813af6ab5fSopenharmony_ci    binder::Variable *enumMember = expr->AsIdentifier()->Variable();
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_ci    if (!enumMember) {
843af6ab5fSopenharmony_ci        checker->ThrowTypeError({"Cannot find name ", expr->AsIdentifier()->Name()},
853af6ab5fSopenharmony_ci                                enumVar->Declaration()->Node()->Start());
863af6ab5fSopenharmony_ci    }
873af6ab5fSopenharmony_ci
883af6ab5fSopenharmony_ci    if (enumMember->IsEnumVariable()) {
893af6ab5fSopenharmony_ci        binder::EnumVariable *exprEnumVar = enumMember->AsEnumVariable();
903af6ab5fSopenharmony_ci        if (std::holds_alternative<bool>(exprEnumVar->Value())) {
913af6ab5fSopenharmony_ci            checker->ThrowTypeError(
923af6ab5fSopenharmony_ci                "A member initializer in a enum declaration cannot reference members declared after it, "
933af6ab5fSopenharmony_ci                "including "
943af6ab5fSopenharmony_ci                "members defined in other enums.",
953af6ab5fSopenharmony_ci                enumVar->Declaration()->Node()->Start());
963af6ab5fSopenharmony_ci        }
973af6ab5fSopenharmony_ci
983af6ab5fSopenharmony_ci        return exprEnumVar->Value();
993af6ab5fSopenharmony_ci    }
1003af6ab5fSopenharmony_ci
1013af6ab5fSopenharmony_ci    return false;
1023af6ab5fSopenharmony_ci}
1033af6ab5fSopenharmony_ci
1043af6ab5fSopenharmony_cibinder::EnumMemberResult EvaluateUnaryExpression(checker::Checker *checker, binder::EnumVariable *enumVar,
1053af6ab5fSopenharmony_ci                                                 const ir::UnaryExpression *expr)
1063af6ab5fSopenharmony_ci{
1073af6ab5fSopenharmony_ci    binder::EnumMemberResult value = TSEnumDeclaration::EvaluateEnumMember(checker, enumVar, expr->Argument());
1083af6ab5fSopenharmony_ci    if (!std::holds_alternative<double>(value)) {
1093af6ab5fSopenharmony_ci        return false;
1103af6ab5fSopenharmony_ci    }
1113af6ab5fSopenharmony_ci
1123af6ab5fSopenharmony_ci    switch (expr->OperatorType()) {
1133af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS: {
1143af6ab5fSopenharmony_ci            return std::get<double>(value);
1153af6ab5fSopenharmony_ci        }
1163af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS: {
1173af6ab5fSopenharmony_ci            return -std::get<double>(value);
1183af6ab5fSopenharmony_ci        }
1193af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_TILDE: {
1203af6ab5fSopenharmony_ci            return static_cast<double>(~ToInt(std::get<double>(value)));
1213af6ab5fSopenharmony_ci        }
1223af6ab5fSopenharmony_ci        default: {
1233af6ab5fSopenharmony_ci            break;
1243af6ab5fSopenharmony_ci        }
1253af6ab5fSopenharmony_ci    }
1263af6ab5fSopenharmony_ci
1273af6ab5fSopenharmony_ci    return false;
1283af6ab5fSopenharmony_ci}
1293af6ab5fSopenharmony_ci
1303af6ab5fSopenharmony_cibinder::EnumMemberResult EvaluateMemberExpression(checker::Checker *checker,
1313af6ab5fSopenharmony_ci                                                  [[maybe_unused]] binder::EnumVariable *enumVar,
1323af6ab5fSopenharmony_ci                                                  const ir::MemberExpression *expr)
1333af6ab5fSopenharmony_ci{
1343af6ab5fSopenharmony_ci    if (checker::Checker::IsConstantMemberAccess(expr->AsExpression())) {
1353af6ab5fSopenharmony_ci        if (expr->Check(checker)->TypeFlags() == checker::TypeFlag::ENUM) {
1363af6ab5fSopenharmony_ci            util::StringView name;
1373af6ab5fSopenharmony_ci            if (!expr->IsComputed()) {
1383af6ab5fSopenharmony_ci                name = expr->Property()->AsIdentifier()->Name();
1393af6ab5fSopenharmony_ci            } else {
1403af6ab5fSopenharmony_ci                ASSERT(checker::Checker::IsStringLike(expr->Property()));
1413af6ab5fSopenharmony_ci                name = reinterpret_cast<const ir::StringLiteral *>(expr->Property())->Str();
1423af6ab5fSopenharmony_ci            }
1433af6ab5fSopenharmony_ci
1443af6ab5fSopenharmony_ci            // TODO(aszilagyi)
1453af6ab5fSopenharmony_ci        }
1463af6ab5fSopenharmony_ci    }
1473af6ab5fSopenharmony_ci
1483af6ab5fSopenharmony_ci    return false;
1493af6ab5fSopenharmony_ci}
1503af6ab5fSopenharmony_ci
1513af6ab5fSopenharmony_cibinder::EnumMemberResult EvaluateBinaryExpression(checker::Checker *checker, binder::EnumVariable *enumVar,
1523af6ab5fSopenharmony_ci                                                  const ir::BinaryExpression *expr)
1533af6ab5fSopenharmony_ci{
1543af6ab5fSopenharmony_ci    binder::EnumMemberResult left =
1553af6ab5fSopenharmony_ci        TSEnumDeclaration::EvaluateEnumMember(checker, enumVar, expr->AsBinaryExpression()->Left());
1563af6ab5fSopenharmony_ci    binder::EnumMemberResult right =
1573af6ab5fSopenharmony_ci        TSEnumDeclaration::EvaluateEnumMember(checker, enumVar, expr->AsBinaryExpression()->Right());
1583af6ab5fSopenharmony_ci    if (std::holds_alternative<double>(left) && std::holds_alternative<double>(right)) {
1593af6ab5fSopenharmony_ci        switch (expr->AsBinaryExpression()->OperatorType()) {
1603af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_BITWISE_OR: {
1613af6ab5fSopenharmony_ci                return static_cast<double>(ToUInt(std::get<double>(left)) | ToUInt(std::get<double>(right)));
1623af6ab5fSopenharmony_ci            }
1633af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_BITWISE_AND: {
1643af6ab5fSopenharmony_ci                return static_cast<double>(ToUInt(std::get<double>(left)) & ToUInt(std::get<double>(right)));
1653af6ab5fSopenharmony_ci            }
1663af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: {
1673af6ab5fSopenharmony_ci                return static_cast<double>(ToUInt(std::get<double>(left)) ^ ToUInt(std::get<double>(right)));
1683af6ab5fSopenharmony_ci            }
1693af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: {
1703af6ab5fSopenharmony_ci                return static_cast<double>(ToInt(std::get<double>(left)) << ToUInt(std::get<double>(right)));
1713af6ab5fSopenharmony_ci            }
1723af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: {
1733af6ab5fSopenharmony_ci                return static_cast<double>(ToInt(std::get<double>(left)) >> ToUInt(std::get<double>(right)));
1743af6ab5fSopenharmony_ci            }
1753af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: {
1763af6ab5fSopenharmony_ci                return static_cast<double>(ToUInt(std::get<double>(left)) >> ToUInt(std::get<double>(right)));
1773af6ab5fSopenharmony_ci            }
1783af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_PLUS: {
1793af6ab5fSopenharmony_ci                return std::get<double>(left) + std::get<double>(right);
1803af6ab5fSopenharmony_ci            }
1813af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_MINUS: {
1823af6ab5fSopenharmony_ci                return std::get<double>(left) - std::get<double>(right);
1833af6ab5fSopenharmony_ci            }
1843af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_MULTIPLY: {
1853af6ab5fSopenharmony_ci                return std::get<double>(left) * std::get<double>(right);
1863af6ab5fSopenharmony_ci            }
1873af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_DIVIDE: {
1883af6ab5fSopenharmony_ci                return std::get<double>(left) / std::get<double>(right);
1893af6ab5fSopenharmony_ci            }
1903af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_MOD: {
1913af6ab5fSopenharmony_ci                return std::fmod(std::get<double>(left), std::get<double>(right));
1923af6ab5fSopenharmony_ci            }
1933af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: {
1943af6ab5fSopenharmony_ci                return std::pow(std::get<double>(left), std::get<double>(right));
1953af6ab5fSopenharmony_ci            }
1963af6ab5fSopenharmony_ci            default: {
1973af6ab5fSopenharmony_ci                break;
1983af6ab5fSopenharmony_ci            }
1993af6ab5fSopenharmony_ci        }
2003af6ab5fSopenharmony_ci
2013af6ab5fSopenharmony_ci        return false;
2023af6ab5fSopenharmony_ci    }
2033af6ab5fSopenharmony_ci
2043af6ab5fSopenharmony_ci    if (std::holds_alternative<util::StringView>(left) && std::holds_alternative<util::StringView>(right) &&
2053af6ab5fSopenharmony_ci        expr->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS) {
2063af6ab5fSopenharmony_ci        std::stringstream ss;
2073af6ab5fSopenharmony_ci        ss << std::get<util::StringView>(left) << std::get<util::StringView>(right);
2083af6ab5fSopenharmony_ci
2093af6ab5fSopenharmony_ci        util::UString res(ss.str(), checker->Allocator());
2103af6ab5fSopenharmony_ci        return res.View();
2113af6ab5fSopenharmony_ci    }
2123af6ab5fSopenharmony_ci
2133af6ab5fSopenharmony_ci    return false;
2143af6ab5fSopenharmony_ci}
2153af6ab5fSopenharmony_ci
2163af6ab5fSopenharmony_cibinder::EnumMemberResult TSEnumDeclaration::EvaluateEnumMember(checker::Checker *checker, binder::EnumVariable *enumVar,
2173af6ab5fSopenharmony_ci                                                               const ir::AstNode *expr)
2183af6ab5fSopenharmony_ci{
2193af6ab5fSopenharmony_ci    switch (expr->Type()) {
2203af6ab5fSopenharmony_ci        case ir::AstNodeType::UNARY_EXPRESSION: {
2213af6ab5fSopenharmony_ci            return EvaluateUnaryExpression(checker, enumVar, expr->AsUnaryExpression());
2223af6ab5fSopenharmony_ci        }
2233af6ab5fSopenharmony_ci        case ir::AstNodeType::BINARY_EXPRESSION: {
2243af6ab5fSopenharmony_ci            return EvaluateBinaryExpression(checker, enumVar, expr->AsBinaryExpression());
2253af6ab5fSopenharmony_ci        }
2263af6ab5fSopenharmony_ci        case ir::AstNodeType::NUMBER_LITERAL: {
2273af6ab5fSopenharmony_ci            return expr->AsNumberLiteral()->Number();
2283af6ab5fSopenharmony_ci        }
2293af6ab5fSopenharmony_ci        case ir::AstNodeType::STRING_LITERAL: {
2303af6ab5fSopenharmony_ci            return expr->AsStringLiteral()->Str();
2313af6ab5fSopenharmony_ci        }
2323af6ab5fSopenharmony_ci        case ir::AstNodeType::IDENTIFIER: {
2333af6ab5fSopenharmony_ci            return EvaluateIdentifier(checker, enumVar, expr->AsIdentifier());
2343af6ab5fSopenharmony_ci        }
2353af6ab5fSopenharmony_ci        case ir::AstNodeType::MEMBER_EXPRESSION: {
2363af6ab5fSopenharmony_ci            return EvaluateEnumMember(checker, enumVar, expr->AsMemberExpression());
2373af6ab5fSopenharmony_ci        }
2383af6ab5fSopenharmony_ci        default:
2393af6ab5fSopenharmony_ci            break;
2403af6ab5fSopenharmony_ci    }
2413af6ab5fSopenharmony_ci
2423af6ab5fSopenharmony_ci    return false;
2433af6ab5fSopenharmony_ci}
2443af6ab5fSopenharmony_ci
2453af6ab5fSopenharmony_cibool IsComputedEnumMember(const ir::Expression *init)
2463af6ab5fSopenharmony_ci{
2473af6ab5fSopenharmony_ci    if (init->IsLiteral()) {
2483af6ab5fSopenharmony_ci        return !init->AsLiteral()->IsStringLiteral() && !init->AsLiteral()->IsNumberLiteral();
2493af6ab5fSopenharmony_ci    }
2503af6ab5fSopenharmony_ci
2513af6ab5fSopenharmony_ci    if (init->IsTemplateLiteral()) {
2523af6ab5fSopenharmony_ci        return !init->AsTemplateLiteral()->Quasis().empty();
2533af6ab5fSopenharmony_ci    }
2543af6ab5fSopenharmony_ci
2553af6ab5fSopenharmony_ci    return true;
2563af6ab5fSopenharmony_ci}
2573af6ab5fSopenharmony_ci
2583af6ab5fSopenharmony_civoid AddEnumValueDeclaration(checker::Checker *checker, double number, binder::EnumVariable *variable)
2593af6ab5fSopenharmony_ci{
2603af6ab5fSopenharmony_ci    variable->SetTsType(checker->GlobalNumberType());
2613af6ab5fSopenharmony_ci
2623af6ab5fSopenharmony_ci    util::StringView memberStr = util::Helpers::ToStringView(checker->Allocator(), number);
2633af6ab5fSopenharmony_ci
2643af6ab5fSopenharmony_ci    binder::TSEnumScope *enumScope = checker->Scope()->AsTSEnumScope();
2653af6ab5fSopenharmony_ci    binder::Variable *res = enumScope->FindEnumMemberVariable(memberStr);
2663af6ab5fSopenharmony_ci    binder::EnumVariable *enumVar = nullptr;
2673af6ab5fSopenharmony_ci
2683af6ab5fSopenharmony_ci    if (!res) {
2693af6ab5fSopenharmony_ci        auto *decl = checker->Allocator()->New<binder::EnumDecl>(memberStr);
2703af6ab5fSopenharmony_ci        CHECK_NOT_NULL(decl);
2713af6ab5fSopenharmony_ci        decl->BindNode(variable->Declaration()->Node());
2723af6ab5fSopenharmony_ci        enumScope->AddDecl(checker->Allocator(), decl, ScriptExtension::TS);
2733af6ab5fSopenharmony_ci        res = enumScope->FindEnumMemberVariable(memberStr);
2743af6ab5fSopenharmony_ci        CHECK_NOT_NULL(res);
2753af6ab5fSopenharmony_ci        ASSERT(res->IsEnumVariable());
2763af6ab5fSopenharmony_ci        enumVar = res->AsEnumVariable();
2773af6ab5fSopenharmony_ci        enumVar->AsEnumVariable()->SetBackReference();
2783af6ab5fSopenharmony_ci        enumVar->SetTsType(checker->GlobalStringType());
2793af6ab5fSopenharmony_ci    } else {
2803af6ab5fSopenharmony_ci        ASSERT(res->IsEnumVariable());
2813af6ab5fSopenharmony_ci        enumVar = res->AsEnumVariable();
2823af6ab5fSopenharmony_ci        auto *decl = checker->Allocator()->New<binder::EnumDecl>(memberStr);
2833af6ab5fSopenharmony_ci        CHECK_NOT_NULL(decl);
2843af6ab5fSopenharmony_ci        decl->BindNode(variable->Declaration()->Node());
2853af6ab5fSopenharmony_ci        enumVar->ResetDecl(decl);
2863af6ab5fSopenharmony_ci    }
2873af6ab5fSopenharmony_ci
2883af6ab5fSopenharmony_ci    enumVar->SetValue(variable->Declaration()->Name());
2893af6ab5fSopenharmony_ci}
2903af6ab5fSopenharmony_ci
2913af6ab5fSopenharmony_civoid InferEnumVariableType(checker::Checker *checker, binder::EnumVariable *variable, double *value, bool *initNext,
2923af6ab5fSopenharmony_ci                           bool *isLiteralEnum, bool isConstEnum, const ir::Expression *computedExpr)
2933af6ab5fSopenharmony_ci{
2943af6ab5fSopenharmony_ci    const ir::Expression *init = variable->Declaration()->Node()->AsTSEnumMember()->Init();
2953af6ab5fSopenharmony_ci
2963af6ab5fSopenharmony_ci    if (!init) {
2973af6ab5fSopenharmony_ci        if (*initNext) {
2983af6ab5fSopenharmony_ci            checker->ThrowTypeError("Enum member must have initializer.", variable->Declaration()->Node()->Start());
2993af6ab5fSopenharmony_ci        } else {
3003af6ab5fSopenharmony_ci            variable->SetValue(++(*value));
3013af6ab5fSopenharmony_ci            AddEnumValueDeclaration(checker, *value, variable);
3023af6ab5fSopenharmony_ci            return;
3033af6ab5fSopenharmony_ci        }
3043af6ab5fSopenharmony_ci    }
3053af6ab5fSopenharmony_ci
3063af6ab5fSopenharmony_ci    if (IsComputedEnumMember(init)) {
3073af6ab5fSopenharmony_ci        if (*isLiteralEnum) {
3083af6ab5fSopenharmony_ci            checker->ThrowTypeError("Computed values are not permitted in an enum with string valued members.",
3093af6ab5fSopenharmony_ci                                    init->Start());
3103af6ab5fSopenharmony_ci        }
3113af6ab5fSopenharmony_ci
3123af6ab5fSopenharmony_ci        computedExpr = init;
3133af6ab5fSopenharmony_ci    }
3143af6ab5fSopenharmony_ci
3153af6ab5fSopenharmony_ci    binder::EnumMemberResult res = TSEnumDeclaration::EvaluateEnumMember(checker, variable, init);
3163af6ab5fSopenharmony_ci    if (std::holds_alternative<util::StringView>(res)) {
3173af6ab5fSopenharmony_ci        if (computedExpr) {
3183af6ab5fSopenharmony_ci            checker->ThrowTypeError("Computed values are not permitted in an enum with string valued members.",
3193af6ab5fSopenharmony_ci                                    computedExpr->Start());
3203af6ab5fSopenharmony_ci        }
3213af6ab5fSopenharmony_ci
3223af6ab5fSopenharmony_ci        *isLiteralEnum = true;
3233af6ab5fSopenharmony_ci        variable->SetTsType(checker->GlobalStringType());
3243af6ab5fSopenharmony_ci        *initNext = true;
3253af6ab5fSopenharmony_ci        return;
3263af6ab5fSopenharmony_ci    }
3273af6ab5fSopenharmony_ci
3283af6ab5fSopenharmony_ci    if (std::holds_alternative<bool>(res)) {
3293af6ab5fSopenharmony_ci        if (isConstEnum) {
3303af6ab5fSopenharmony_ci            checker->ThrowTypeError(
3313af6ab5fSopenharmony_ci                "const enum member initializers can only contain literal values and other computed enum "
3323af6ab5fSopenharmony_ci                "values.",
3333af6ab5fSopenharmony_ci                init->Start());
3343af6ab5fSopenharmony_ci        }
3353af6ab5fSopenharmony_ci
3363af6ab5fSopenharmony_ci        *initNext = true;
3373af6ab5fSopenharmony_ci        return;
3383af6ab5fSopenharmony_ci    }
3393af6ab5fSopenharmony_ci
3403af6ab5fSopenharmony_ci    ASSERT(std::holds_alternative<double>(res));
3413af6ab5fSopenharmony_ci    variable->SetValue(res);
3423af6ab5fSopenharmony_ci
3433af6ab5fSopenharmony_ci    *value = std::get<double>(res);
3443af6ab5fSopenharmony_ci    if (isConstEnum) {
3453af6ab5fSopenharmony_ci        if (std::isnan(*value)) {
3463af6ab5fSopenharmony_ci            checker->ThrowTypeError("'const' enum member initializer was evaluated to disallowed value 'NaN'.",
3473af6ab5fSopenharmony_ci                                    init->Start());
3483af6ab5fSopenharmony_ci        }
3493af6ab5fSopenharmony_ci
3503af6ab5fSopenharmony_ci        if (std::isinf(*value)) {
3513af6ab5fSopenharmony_ci            checker->ThrowTypeError("'const' enum member initializer was evaluated to a non-finite value.",
3523af6ab5fSopenharmony_ci                                    init->Start());
3533af6ab5fSopenharmony_ci        }
3543af6ab5fSopenharmony_ci    }
3553af6ab5fSopenharmony_ci
3563af6ab5fSopenharmony_ci    *initNext = false;
3573af6ab5fSopenharmony_ci    AddEnumValueDeclaration(checker, *value, variable);
3583af6ab5fSopenharmony_ci}
3593af6ab5fSopenharmony_ci
3603af6ab5fSopenharmony_cichecker::Type *TSEnumDeclaration::InferType(checker::Checker *checker, bool isConst) const
3613af6ab5fSopenharmony_ci{
3623af6ab5fSopenharmony_ci    double value = -1.0;
3633af6ab5fSopenharmony_ci
3643af6ab5fSopenharmony_ci    binder::TSEnumScope *enumScope = checker->Scope()->AsTSEnumScope();
3653af6ab5fSopenharmony_ci
3663af6ab5fSopenharmony_ci    bool initNext = false;
3673af6ab5fSopenharmony_ci    bool isLiteralEnum = false;
3683af6ab5fSopenharmony_ci    const ir::Expression *computedExpr = nullptr;
3693af6ab5fSopenharmony_ci    size_t localsSize = enumScope->Decls().size();
3703af6ab5fSopenharmony_ci
3713af6ab5fSopenharmony_ci    for (size_t i = 0; i < localsSize; i++) {
3723af6ab5fSopenharmony_ci        const util::StringView &currentName = enumScope->Decls()[i]->Name();
3733af6ab5fSopenharmony_ci        binder::Variable *currentVar = enumScope->FindEnumMemberVariable(currentName);
3743af6ab5fSopenharmony_ci        CHECK_NOT_NULL(currentVar);
3753af6ab5fSopenharmony_ci        ASSERT(currentVar->IsEnumVariable());
3763af6ab5fSopenharmony_ci        InferEnumVariableType(checker, currentVar->AsEnumVariable(), &value, &initNext, &isLiteralEnum, isConst,
3773af6ab5fSopenharmony_ci                              computedExpr);
3783af6ab5fSopenharmony_ci    }
3793af6ab5fSopenharmony_ci
3803af6ab5fSopenharmony_ci    checker::Type *enumType = checker->Allocator()->New<checker::EnumLiteralType>(
3813af6ab5fSopenharmony_ci        key_->Name(), checker->Scope(),
3823af6ab5fSopenharmony_ci        isLiteralEnum ? checker::EnumLiteralType::EnumLiteralTypeKind::LITERAL
3833af6ab5fSopenharmony_ci                      : checker::EnumLiteralType::EnumLiteralTypeKind::NUMERIC);
3843af6ab5fSopenharmony_ci
3853af6ab5fSopenharmony_ci    return enumType;
3863af6ab5fSopenharmony_ci}
3873af6ab5fSopenharmony_ci
3883af6ab5fSopenharmony_cichecker::Type *TSEnumDeclaration::Check(checker::Checker *checker) const
3893af6ab5fSopenharmony_ci{
3903af6ab5fSopenharmony_ci    binder::Variable *enumVar = key_->Variable();
3913af6ab5fSopenharmony_ci    // TODO: enumLiteral Identifier binds enumLiteral Variable.
3923af6ab5fSopenharmony_ci    if (enumVar == nullptr) {
3933af6ab5fSopenharmony_ci        return nullptr;
3943af6ab5fSopenharmony_ci    }
3953af6ab5fSopenharmony_ci
3963af6ab5fSopenharmony_ci    if (!enumVar->TsType()) {
3973af6ab5fSopenharmony_ci        checker::ScopeContext scopeCtx(checker, scope_);
3983af6ab5fSopenharmony_ci        checker::Type *enumType = InferType(checker, isConst_);
3993af6ab5fSopenharmony_ci        CHECK_NOT_NULL(enumType);
4003af6ab5fSopenharmony_ci        enumType->SetVariable(enumVar);
4013af6ab5fSopenharmony_ci        enumVar->SetTsType(enumType);
4023af6ab5fSopenharmony_ci    }
4033af6ab5fSopenharmony_ci
4043af6ab5fSopenharmony_ci    return nullptr;
4053af6ab5fSopenharmony_ci}
4063af6ab5fSopenharmony_ci
4073af6ab5fSopenharmony_civoid TSEnumDeclaration::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
4083af6ab5fSopenharmony_ci{
4093af6ab5fSopenharmony_ci    key_ = std::get<ir::AstNode *>(cb(key_))->AsIdentifier();
4103af6ab5fSopenharmony_ci
4113af6ab5fSopenharmony_ci    for (auto iter = members_.begin(); iter != members_.end(); iter++) {
4123af6ab5fSopenharmony_ci        *iter = std::get<ir::AstNode *>(cb(*iter))->AsTSEnumMember();
4133af6ab5fSopenharmony_ci    }
4143af6ab5fSopenharmony_ci}
4153af6ab5fSopenharmony_ci
4163af6ab5fSopenharmony_ci}  // namespace panda::es2panda::ir
417