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 ¤tName = 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