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 "enumLowering.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 25namespace { 26 27[[nodiscard]] ir::ETSParameterExpression *MakeFunctionParam(checker::ETSChecker *const checker, 28 varbinder::ETSBinder *const varbinder, 29 varbinder::FunctionParamScope *const scope, 30 const util::StringView &name, 31 ir::TypeNode *const typeAnnotation) 32{ 33 const auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(varbinder, scope, false); 34 auto *const paramIdent = checker->AllocNode<ir::Identifier>(name, typeAnnotation, checker->Allocator()); 35 auto *const param = checker->AllocNode<ir::ETSParameterExpression>(paramIdent, nullptr); 36 auto *const paramVar = std::get<1>(varbinder->AddParamDecl(param)); 37 param->Ident()->SetVariable(paramVar); 38 return param; 39} 40 41[[nodiscard]] ir::Identifier *MakeParamRefIdent(checker::ETSChecker *const checker, 42 ir::ETSParameterExpression *paramExpr) 43{ 44 auto *const refIdent = checker->AllocNode<ir::Identifier>(paramExpr->Ident()->Name(), checker->Allocator()); 45 refIdent->SetVariable(paramExpr->Ident()->Variable()); 46 return refIdent; 47} 48 49[[nodiscard]] ir::ETSTypeReference *MakeTypeReference(checker::ETSChecker *const checker, const util::StringView &name) 50{ 51 auto *const ident = checker->AllocNode<ir::Identifier>(name, checker->Allocator()); 52 ident->SetReference(); 53 auto *const referencePart = checker->AllocNode<ir::ETSTypeReferencePart>(ident); 54 return checker->AllocNode<ir::ETSTypeReference>(referencePart); 55} 56 57ir::MethodDefinition *MakeMethodDef(checker::ETSChecker *const checker, ir::ClassDefinition *enumClass, 58 varbinder::ETSBinder *const varbinder, ir::Identifier *const ident, 59 ir::ScriptFunction *const function) 60{ 61 auto *const functionExpr = checker->AllocNode<ir::FunctionExpression>(function); 62 auto *const identClone = ident->Clone(checker->Allocator(), nullptr); 63 64 auto *const methodDef = checker->AllocNode<ir::MethodDefinition>( 65 ir::MethodDefinitionKind::METHOD, identClone, functionExpr, function->Modifiers(), checker->Allocator(), false); 66 methodDef->SetParent(enumClass); 67 enumClass->Body().push_back(methodDef); 68 69 auto classCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter( 70 varbinder, enumClass->Scope()->AsClassScope()->StaticMethodScope()); 71 72 auto *const methodVar = std::get<1>(varbinder->NewVarDecl<varbinder::FunctionDecl>( 73 methodDef->Start(), checker->Allocator(), methodDef->Id()->Name(), methodDef)); 74 75 varbinder::VariableFlags varFlags = varbinder::VariableFlags::SYNTHETIC | varbinder::VariableFlags::METHOD; 76 if ((function->Modifiers() & ir::ModifierFlags::STATIC) != 0) { 77 varFlags |= varbinder::VariableFlags::STATIC; 78 } 79 80 methodVar->AddFlag(varFlags); 81 methodDef->Function()->Id()->SetVariable(methodVar); 82 methodDef->Id()->SetVariable(methodVar); 83 return methodDef; 84} 85 86} // namespace 87 88[[nodiscard]] ir::ScriptFunction *EnumLoweringPhase::MakeFunction(FunctionInfo &&functionInfo) 89{ 90 auto *const functionScope = 91 varbinder_->Allocator()->New<varbinder::FunctionScope>(Allocator(), functionInfo.paramScope); 92 functionScope->BindParamScope(functionInfo.paramScope); 93 functionInfo.paramScope->BindFunctionScope(functionScope); 94 ir::BlockStatement *bodyBlock = nullptr; 95 96 if (functionInfo.enumDecl->IsDeclare()) { 97 functionInfo.flags |= ir::ModifierFlags::DECLARE; 98 } else { 99 bodyBlock = checker_->AllocNode<ir::BlockStatement>(Allocator(), std::move(functionInfo.body)); 100 bodyBlock->SetScope(functionScope); 101 } 102 // clang-format off 103 auto *const function = checker_->AllocNode<ir::ScriptFunction>( 104 Allocator(), ir::ScriptFunction::ScriptFunctionData { 105 bodyBlock, 106 ir::FunctionSignature(nullptr, std::move(functionInfo.params), functionInfo.returnTypeAnnotation), 107 ir::ScriptFunctionFlags::METHOD, functionInfo.flags, functionInfo.enumDecl->IsDeclare()}); 108 // clang-format on 109 function->SetScope(functionScope); 110 111 if (!function->Declare()) { 112 varbinder_->AsETSBinder()->AddCompilableFunction(function); 113 } 114 functionInfo.paramScope->BindNode(function); 115 functionScope->BindNode(function); 116 117 return function; 118} 119 120util::UString EnumLoweringPhase::GetEnumClassName(checker::ETSChecker *checker, 121 const ir::TSEnumDeclaration *const enumDecl) 122{ 123 util::UString className(util::StringView("#"), checker->Allocator()); 124 className.Append(enumDecl->Key()->Name()); 125 return className; 126} 127 128template <typename ElementMaker> 129[[nodiscard]] ir::Identifier *EnumLoweringPhase::MakeArray(const ir::TSEnumDeclaration *const enumDecl, 130 ir::ClassDefinition *const enumClass, 131 const util::StringView &name, 132 ir::TypeNode *const typeAnnotation, 133 ElementMaker &&elementMaker) 134{ 135 auto fieldCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter( 136 varbinder_, enumClass->Scope()->AsClassScope()->StaticFieldScope()); 137 ArenaVector<ir::Expression *> elements(Allocator()->Adapter()); 138 elements.reserve(enumDecl->Members().size()); 139 for (const auto *const member : enumDecl->Members()) { 140 elements.push_back(elementMaker(member->AsTSEnumMember())); 141 } 142 auto *const arrayExpr = checker_->AllocNode<ir::ArrayExpression>(std::move(elements), Allocator()); 143 auto *const arrayIdent = checker_->AllocNode<ir::Identifier>(name, Allocator()); 144 auto *const arrayClassProp = checker_->AllocNode<ir::ClassProperty>( 145 arrayIdent, arrayExpr, typeAnnotation, 146 ir::ModifierFlags::STATIC | ir::ModifierFlags::PROTECTED | ir::ModifierFlags::CONST, Allocator(), false); 147 arrayClassProp->SetParent(enumClass); 148 enumClass->Body().push_back(arrayClassProp); 149 150 auto [array_decl, array_var] = 151 varbinder_->NewVarDecl<varbinder::ConstDecl>(arrayIdent->Start(), arrayIdent->Name(), arrayClassProp); 152 arrayIdent->SetVariable(array_var); 153 array_var->AddFlag(varbinder::VariableFlags::PROTECTED | varbinder::VariableFlags::STATIC | 154 varbinder::VariableFlags::PROPERTY); 155 array_var->SetScope(enumClass->Scope()->AsClassScope()->StaticFieldScope()); 156 array_decl->Node()->SetParent(enumClass); 157 return arrayIdent; 158} 159 160ir::Identifier *EnumLoweringPhase::CreateEnumNamesArray(const ir::TSEnumDeclaration *const enumDecl, 161 ir::ClassDefinition *const enumClass) 162{ 163 auto *const stringTypeAnnotation = MakeTypeReference(checker_, "String"); // NOTE String -> Builtin? 164 auto *const arrayTypeAnnotation = checker_->AllocNode<ir::TSArrayType>(stringTypeAnnotation); 165 166 // clang-format off 167 return MakeArray(enumDecl, enumClass, "NamesArray", arrayTypeAnnotation, 168 [this](const ir::TSEnumMember *const member) { 169 auto *const enumNameStringLiteral = 170 checker_->AllocNode<ir::StringLiteral>(member->Key()->AsIdentifier()->Name()); 171 return enumNameStringLiteral; 172 }); 173 // clang-format on 174} 175 176ir::ClassDefinition *EnumLoweringPhase::CreateClass(ir::TSEnumDeclaration *const enumDecl) 177{ 178 auto globalCtx = varbinder::LexicalScope<varbinder::GlobalScope>::Enter(varbinder_, program_->GlobalScope()); 179 auto *ident = Allocator()->New<ir::Identifier>(GetEnumClassName(checker_, enumDecl).View(), Allocator()); 180 auto [decl, var] = varbinder_->NewVarDecl<varbinder::ClassDecl>(ident->Start(), ident->Name()); 181 ident->SetVariable(var); 182 183 auto classCtx = varbinder::LexicalScope<varbinder::ClassScope>(varbinder_); 184 auto *classDef = checker_->AllocNode<ir::ClassDefinition>( 185 Allocator(), ident, 186 enumDecl->IsDeclare() ? ir::ClassDefinitionModifiers::DECLARATION : ir::ClassDefinitionModifiers::NONE, 187 enumDecl->IsDeclare() ? ir::ModifierFlags::DECLARE : ir::ModifierFlags::NONE, Language(Language::Id::ETS)); 188 189 classDef->SetScope(classCtx.GetScope()); 190 auto *classDecl = checker_->AllocNode<ir::ClassDeclaration>(classDef, Allocator()); 191 classDef->Scope()->BindNode(classDef); 192 decl->BindNode(classDecl); 193 program_->Ast()->Statements().push_back(classDecl); 194 classDecl->SetParent(program_->Ast()); 195 enumDecl->SetBoxedClass(classDef); 196 197 CreateOrdinalField(classDef); 198 CreateCCtorForEnumClass(classDef); 199 CreateCtorForEnumClass(classDef); 200 201 return classDef; 202} 203 204void EnumLoweringPhase::CreateCCtorForEnumClass(ir::ClassDefinition *const enumClass) 205{ 206 ArenaVector<ir::Expression *> params(Allocator()->Adapter()); 207 auto *id = checker_->AllocNode<ir::Identifier>(compiler::Signatures::CCTOR, Allocator()); 208 209 auto *const paramScope = 210 varbinder_->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), program_->GlobalScope()); 211 auto *const functionScope = varbinder_->Allocator()->New<varbinder::FunctionScope>(Allocator(), paramScope); 212 functionScope->BindParamScope(paramScope); 213 paramScope->BindFunctionScope(functionScope); 214 215 ArenaVector<ir::Statement *> statements(Allocator()->Adapter()); 216 217 auto *body = checker_->AllocNode<ir::BlockStatement>(Allocator(), std::move(statements)); 218 auto *func = checker_->AllocNode<ir::ScriptFunction>( 219 Allocator(), 220 ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr), 221 ir::ScriptFunctionFlags::STATIC_BLOCK | ir::ScriptFunctionFlags::HIDDEN, 222 ir::ModifierFlags::STATIC, false, Language(Language::Id::ETS)}); 223 224 func->SetIdent(id); 225 id->SetParent(func); 226 body->SetScope(functionScope); 227 func->SetScope(functionScope); 228 auto *funcExpr = checker_->AllocNode<ir::FunctionExpression>(func); 229 230 varbinder_->AsETSBinder()->AddCompilableFunction(func); 231 functionScope->BindNode(func); 232 paramScope->BindNode(func); 233 234 auto *const identClone = id->Clone(Allocator(), nullptr); 235 auto *const methodDef = checker_->AllocNode<ir::MethodDefinition>( 236 ir::MethodDefinitionKind::METHOD, identClone, funcExpr, ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC, 237 Allocator(), false); 238 methodDef->SetParent(enumClass); 239 enumClass->Body().push_back(methodDef); 240 241 auto classCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter( 242 varbinder_, enumClass->Scope()->AsClassScope()->StaticMethodScope()); 243 auto *const methodVar = std::get<1>(varbinder_->NewVarDecl<varbinder::FunctionDecl>( 244 methodDef->Start(), Allocator(), methodDef->Id()->Name(), methodDef)); 245 methodVar->AddFlag(varbinder::VariableFlags::STATIC | varbinder::VariableFlags::SYNTHETIC | 246 varbinder::VariableFlags::METHOD); 247 methodDef->Function()->Id()->SetVariable(methodVar); 248 methodDef->Id()->SetVariable(methodVar); 249} 250 251ir::ClassProperty *EnumLoweringPhase::CreateOrdinalField(ir::ClassDefinition *const enumClass) 252{ 253 auto fieldCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter( 254 varbinder_, enumClass->Scope()->AsClassScope()->InstanceFieldScope()); 255 256 auto *const fieldIdent = Allocator()->New<ir::Identifier>("ordinal", Allocator()); 257 auto *const intTypeAnnotation = Allocator()->New<ir::ETSPrimitiveType>(ir::PrimitiveType::INT); 258 auto *field = checker_->AllocNode<ir::ClassProperty>(fieldIdent, nullptr, intTypeAnnotation, 259 ir::ModifierFlags::PROTECTED, Allocator(), false); 260 261 auto [decl, var] = varbinder_->NewVarDecl<varbinder::LetDecl>(lexer::SourcePosition(), fieldIdent->Name()); 262 var->SetScope(enumClass->Scope()->AsClassScope()->InstanceFieldScope()); 263 var->AddFlag(varbinder::VariableFlags::PROPERTY | varbinder::VariableFlags::PROTECTED); 264 fieldIdent->SetVariable(var); 265 decl->BindNode(field); 266 267 enumClass->Body().push_back(field); 268 field->SetParent(enumClass); 269 return field; 270} 271 272void EnumLoweringPhase::CreateCtorForEnumClass(ir::ClassDefinition *const enumClass) 273{ 274 auto *const paramScope = 275 varbinder_->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), program_->GlobalScope()); 276 277 ArenaVector<ir::Expression *> params(Allocator()->Adapter()); 278 279 auto *const intTypeAnnotation = checker_->AllocNode<ir::ETSPrimitiveType>(ir::PrimitiveType::INT); 280 auto *const inputOrdinalParam = MakeFunctionParam(checker_, varbinder_, paramScope, "ordinal", intTypeAnnotation); 281 params.push_back(inputOrdinalParam); 282 283 auto *id = checker_->AllocNode<ir::Identifier>("constructor", Allocator()); 284 auto *const functionScope = varbinder_->Allocator()->New<varbinder::FunctionScope>(Allocator(), paramScope); 285 functionScope->BindParamScope(paramScope); 286 paramScope->BindFunctionScope(functionScope); 287 ArenaVector<ir::Statement *> statements(Allocator()->Adapter()); 288 289 auto *body = checker_->AllocNode<ir::BlockStatement>(Allocator(), std::move(statements)); 290 auto *func = checker_->AllocNode<ir::ScriptFunction>( 291 Allocator(), 292 ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr), 293 ir::ScriptFunctionFlags::CONSTRUCTOR, ir::ModifierFlags::CONSTRUCTOR, 294 false, Language(Language::Id::ETS)}); 295 296 func->SetIdent(id); 297 body->SetScope(functionScope); 298 func->SetScope(functionScope); 299 auto *funcExpr = checker_->AllocNode<ir::FunctionExpression>(func); 300 301 varbinder_->AsETSBinder()->AddCompilableFunction(func); 302 functionScope->BindNode(func); 303 paramScope->BindNode(func); 304 305 auto *thisExpr = Allocator()->New<ir::ThisExpression>(); 306 auto *fieldIdentifier = Allocator()->New<ir::Identifier>("ordinal", Allocator()); 307 fieldIdentifier->SetReference(); 308 auto *leftHandSide = checker_->AllocNode<ir::MemberExpression>( 309 thisExpr, fieldIdentifier, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); 310 auto *rightHandSide = checker_->AllocNode<ir::Identifier>("ordinal", Allocator()); 311 rightHandSide->SetVariable(inputOrdinalParam->Ident()->Variable()); 312 auto *initializer = checker_->AllocNode<ir::AssignmentExpression>(leftHandSide, rightHandSide, 313 lexer::TokenType::PUNCTUATOR_SUBSTITUTION); 314 auto initStatement = checker_->AllocNode<ir::ExpressionStatement>(initializer); 315 initStatement->SetParent(body); 316 body->Statements().push_back(initStatement); 317 318 auto *const identClone = id->Clone(Allocator(), nullptr); 319 auto *const methodDef = checker_->AllocNode<ir::MethodDefinition>( 320 ir::MethodDefinitionKind::CONSTRUCTOR, identClone, funcExpr, ir::ModifierFlags::PUBLIC, Allocator(), false); 321 methodDef->SetParent(enumClass); 322 enumClass->Body().push_back(methodDef); 323 324 auto classCtx = varbinder::LexicalScope<varbinder::LocalScope>::Enter( 325 varbinder_, enumClass->Scope()->AsClassScope()->StaticMethodScope()); 326 auto *const methodVar = std::get<1>(varbinder_->NewVarDecl<varbinder::FunctionDecl>( 327 methodDef->Start(), Allocator(), methodDef->Id()->Name(), methodDef)); 328 methodVar->AddFlag(varbinder::VariableFlags::SYNTHETIC | varbinder::VariableFlags::METHOD); 329 methodDef->Function()->Id()->SetVariable(methodVar); 330 methodDef->Id()->SetVariable(methodVar); 331} 332 333void EnumLoweringPhase::CreateEnumIntClassFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl) 334{ 335 auto *const enumClass = CreateClass(enumDecl); 336 auto *const namesArrayIdent = CreateEnumNamesArray(enumDecl, enumClass); 337 auto *const valuesArrayIdent = CreateEnumValuesArray(enumDecl, enumClass); 338 auto *const stringValuesArrayIdent = CreateEnumStringValuesArray(enumDecl, enumClass); 339 auto *const itemsArrayIdent = CreateEnumItemsArray(enumDecl, enumClass); 340 auto *const boxedItemsArrayIdent = CreateBoxedEnumItemsArray(enumDecl, enumClass); 341 342 auto *identClone = namesArrayIdent->Clone(Allocator(), nullptr); 343 CreateEnumGetNameMethod(enumDecl, enumClass, identClone); 344 345 identClone = namesArrayIdent->Clone(Allocator(), nullptr); 346 CreateEnumGetValueOfMethod(enumDecl, enumClass, identClone); 347 348 identClone = valuesArrayIdent->Clone(Allocator(), nullptr); 349 CreateEnumValueOfMethod(enumDecl, enumClass, identClone); 350 351 identClone = stringValuesArrayIdent->Clone(Allocator(), nullptr); 352 CreateEnumToStringMethod(enumDecl, enumClass, identClone); 353 354 identClone = itemsArrayIdent->Clone(Allocator(), nullptr); 355 CreateEnumValuesMethod(enumDecl, enumClass, identClone); 356 357 identClone = itemsArrayIdent->Clone(Allocator(), nullptr); 358 CreateEnumFromIntMethod(enumDecl, enumClass, identClone, checker::ETSEnumType::FROM_INT_METHOD_NAME, 359 enumDecl->Key()->Name()); 360 361 identClone = itemsArrayIdent->Clone(Allocator(), nullptr); 362 CreateUnboxingMethod(enumDecl, enumClass, identClone); 363 364 identClone = boxedItemsArrayIdent->Clone(Allocator(), nullptr); 365 CreateEnumFromIntMethod(enumDecl, enumClass, identClone, checker::ETSEnumType::BOXED_FROM_INT_METHOD_NAME, 366 GetEnumClassName(checker_, enumDecl).View()); 367} 368 369void EnumLoweringPhase::CreateEnumStringClassFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl) 370{ 371 auto *const enumClass = CreateClass(enumDecl); 372 auto *const namesArrayIdent = CreateEnumNamesArray(enumDecl, enumClass); 373 auto *const stringValuesArrayIdent = CreateEnumStringValuesArray(enumDecl, enumClass); 374 auto *const itemsArrayIdent = CreateEnumItemsArray(enumDecl, enumClass); 375 auto *const boxedItemsArrayIdent = CreateBoxedEnumItemsArray(enumDecl, enumClass); 376 377 auto *identClone = namesArrayIdent->Clone(Allocator(), nullptr); 378 CreateEnumGetNameMethod(enumDecl, enumClass, identClone); 379 380 identClone = namesArrayIdent->Clone(Allocator(), nullptr); 381 CreateEnumGetValueOfMethod(enumDecl, enumClass, identClone); 382 383 identClone = stringValuesArrayIdent->Clone(Allocator(), nullptr); 384 CreateEnumToStringMethod(enumDecl, enumClass, identClone); 385 386 identClone = itemsArrayIdent->Clone(Allocator(), nullptr); 387 CreateEnumValuesMethod(enumDecl, enumClass, identClone); 388 389 identClone = itemsArrayIdent->Clone(Allocator(), nullptr); 390 CreateEnumFromIntMethod(enumDecl, enumClass, identClone, checker::ETSEnumType::FROM_INT_METHOD_NAME, 391 enumDecl->Key()->Name()); 392 393 identClone = itemsArrayIdent->Clone(Allocator(), nullptr); 394 CreateUnboxingMethod(enumDecl, enumClass, identClone); 395 396 identClone = boxedItemsArrayIdent->Clone(Allocator(), nullptr); 397 CreateEnumFromIntMethod(enumDecl, enumClass, identClone, checker::ETSEnumType::BOXED_FROM_INT_METHOD_NAME, 398 GetEnumClassName(checker_, enumDecl).View()); 399} 400 401bool EnumLoweringPhase::Perform(public_lib::Context *ctx, parser::Program *program) 402{ 403 bool isPerformedSuccess = true; 404 if (program->Extension() != ScriptExtension::ETS) { 405 return isPerformedSuccess; 406 } 407 408 for (auto &[_, extPrograms] : program->ExternalSources()) { 409 (void)_; 410 for (auto *extProg : extPrograms) { 411 isPerformedSuccess &= Perform(ctx, extProg); 412 } 413 } 414 415 checker_ = ctx->checker->AsETSChecker(); 416 varbinder_ = ctx->parserProgram->VarBinder()->AsETSBinder(); 417 program_ = program; 418 program->Ast()->IterateRecursively([this, &isPerformedSuccess](ir::AstNode *ast) -> void { 419 if (ast->IsTSEnumDeclaration()) { 420 auto *enumDecl = ast->AsTSEnumDeclaration(); 421 422 if (auto *const itemInit = enumDecl->Members().front()->AsTSEnumMember()->Init(); 423 itemInit->IsNumberLiteral()) { 424 CreateEnumIntClassFromEnumDeclaration(enumDecl); 425 } else if (itemInit->IsStringLiteral()) { 426 CreateEnumStringClassFromEnumDeclaration(enumDecl); 427 } else { 428 checker_->LogTypeError("Invalid enumeration value type.", enumDecl->Start()); 429 isPerformedSuccess = false; 430 } 431 } 432 }); 433 return isPerformedSuccess; 434} 435 436ir::Identifier *EnumLoweringPhase::CreateEnumValuesArray(const ir::TSEnumDeclaration *const enumDecl, 437 ir::ClassDefinition *const enumClass) 438{ 439 auto *const intType = checker_->AllocNode<ir::ETSPrimitiveType>(ir::PrimitiveType::INT); 440 auto *const arrayTypeAnnotation = checker_->AllocNode<ir::TSArrayType>(intType); 441 // clang-format off 442 return MakeArray(enumDecl, enumClass, "ValuesArray", arrayTypeAnnotation, 443 [this](const ir::TSEnumMember *const member) { 444 auto *const enumValueLiteral = checker_->AllocNode<ir::NumberLiteral>( 445 lexer::Number(member->AsTSEnumMember() 446 ->Init() 447 ->AsNumberLiteral() 448 ->Number() 449 .GetValue<checker::ETSIntEnumType::ValueType>())); 450 return enumValueLiteral; 451 }); 452 // clang-format on 453} 454 455ir::Identifier *EnumLoweringPhase::CreateEnumStringValuesArray(const ir::TSEnumDeclaration *const enumDecl, 456 ir::ClassDefinition *const enumClass) 457{ 458 auto *const stringTypeAnnotation = MakeTypeReference(checker_, "String"); // NOTE String -> Builtin? 459 auto *const arrayTypeAnnotation = checker_->AllocNode<ir::TSArrayType>(stringTypeAnnotation); 460 461 // clang-format off 462 return MakeArray(enumDecl, enumClass, "StringValuesArray", arrayTypeAnnotation, 463 [this](const ir::TSEnumMember *const member) { 464 auto *const init = member->AsTSEnumMember()->Init(); 465 util::StringView stringValue; 466 467 if (init->IsStringLiteral()) { 468 stringValue = init->AsStringLiteral()->Str(); 469 } else { 470 auto str = std::to_string( 471 init->AsNumberLiteral()->Number().GetValue<checker::ETSIntEnumType::ValueType>()); 472 stringValue = util::UString(str, Allocator()).View(); 473 } 474 475 auto *const enumValueStringLiteral = checker_->AllocNode<ir::StringLiteral>(stringValue); 476 return enumValueStringLiteral; 477 }); 478 // clang-format on 479} 480 481ir::Identifier *EnumLoweringPhase::CreateEnumItemsArray(const ir::TSEnumDeclaration *const enumDecl, 482 ir::ClassDefinition *const enumClass) 483{ 484 auto *const enumTypeAnnotation = MakeTypeReference(checker_, enumDecl->Key()->Name()); 485 auto *const arrayTypeAnnotation = checker_->AllocNode<ir::TSArrayType>(enumTypeAnnotation); 486 // clang-format off 487 return MakeArray(enumDecl, enumClass, "ItemsArray", arrayTypeAnnotation, 488 [this, enumDecl](const ir::TSEnumMember *const member) { 489 auto *const enumTypeIdent = 490 checker_->AllocNode<ir::Identifier>(enumDecl->Key()->Name(), Allocator()); 491 enumTypeIdent->SetReference(); 492 493 auto *const enumMemberIdent = checker_->AllocNode<ir::Identifier>( 494 member->AsTSEnumMember()->Key()->AsIdentifier()->Name(), Allocator()); 495 enumMemberIdent->SetReference(); 496 auto *const enumMemberExpr = checker_->AllocNode<ir::MemberExpression>( 497 enumTypeIdent, enumMemberIdent, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); 498 return enumMemberExpr; 499 }); 500 // clang-format on 501} 502 503ir::Identifier *EnumLoweringPhase::CreateBoxedEnumItemsArray(const ir::TSEnumDeclaration *const enumDecl, 504 ir::ClassDefinition *const enumClass) 505{ 506 auto boxedClassName = GetEnumClassName(checker_, enumDecl).View(); 507 auto *const enumTypeAnnotation = MakeTypeReference(checker_, boxedClassName); 508 auto *const arrayTypeAnnotation = checker_->AllocNode<ir::TSArrayType>(enumTypeAnnotation); 509 // clang-format off 510 return MakeArray(enumDecl, enumClass, "BoxedItemsArray", arrayTypeAnnotation, 511 [this, enumDecl, &boxedClassName](const ir::TSEnumMember *const member) { 512 auto *const enumTypeIdent = 513 checker_->AllocNode<ir::Identifier>(enumDecl->Key()->Name(), Allocator()); 514 enumTypeIdent->SetReference(); 515 516 auto *const enumMemberIdent = checker_->AllocNode<ir::Identifier>( 517 member->AsTSEnumMember()->Key()->AsIdentifier()->Name(), Allocator()); 518 enumMemberIdent->SetReference(); 519 auto *const enumMemberExpr = checker_->AllocNode<ir::MemberExpression>( 520 enumTypeIdent, enumMemberIdent, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); 521 522 auto intType = checker_->AllocNode<ir::ETSPrimitiveType>(ir::PrimitiveType::INT); 523 auto asExpression = checker_->AllocNode<ir::TSAsExpression>(enumMemberExpr, intType, false); 524 525 ArenaVector<ir::Expression *> newExprArgs(Allocator()->Adapter()); 526 newExprArgs.push_back(asExpression); 527 528 auto boxedTypeRef = MakeTypeReference(checker_, boxedClassName); 529 530 auto *const newExpression = checker_->AllocNode<ir::ETSNewClassInstanceExpression>( 531 boxedTypeRef, std::move(newExprArgs), nullptr); 532 return newExpression; 533 }); 534 // clang-format on 535} 536 537namespace { 538 539ir::BinaryExpression *CreateIfTest(EnumLoweringPhase *const elp, ir::Identifier *const itemsArrayIdentifier, 540 ir::ETSParameterExpression *const parameter) 541{ 542 auto *const checker = elp->Checker(); 543 auto *const lengthIdent = checker->AllocNode<ir::Identifier>("length", checker->Allocator()); 544 lengthIdent->SetReference(); 545 auto *const valuesArrayLengthExpr = checker->AllocNode<ir::MemberExpression>( 546 itemsArrayIdentifier, lengthIdent, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); 547 auto *const paramRefIdent = MakeParamRefIdent(checker, parameter); 548 auto *const expr = checker->AllocNode<ir::BinaryExpression>(paramRefIdent, valuesArrayLengthExpr, 549 lexer::TokenType::PUNCTUATOR_LESS_THAN); 550 paramRefIdent->SetParent(expr); 551 return expr; 552} 553ir::ReturnStatement *CreateReturnEnumStatement(EnumLoweringPhase *const elp, ir::Identifier *const itemsArrayIdentifier, 554 ir::ETSParameterExpression *const parameter) 555{ 556 auto *const checker = elp->Checker(); 557 auto *const paramRefIdent = MakeParamRefIdent(checker, parameter); 558 auto itemsArrayIdentClone = itemsArrayIdentifier->Clone(checker->Allocator(), nullptr); 559 auto *const arrayAccessExpr = checker->AllocNode<ir::MemberExpression>( 560 itemsArrayIdentClone, paramRefIdent, ir::MemberExpressionKind::ELEMENT_ACCESS, true, false); 561 auto *const returnStatement = checker->AllocNode<ir::ReturnStatement>(arrayAccessExpr); 562 return returnStatement; 563} 564 565ir::ThrowStatement *CreateThrowStatement(EnumLoweringPhase *const elp, ir::ETSParameterExpression *const parameter, 566 const util::UString &messageString) 567{ 568 auto *const checker = elp->Checker(); 569 570 auto *const paramRefIdent = MakeParamRefIdent(checker, parameter); 571 auto *const message = checker->AllocNode<ir::StringLiteral>(messageString.View()); 572 auto *const newExprArg = 573 checker->AllocNode<ir::BinaryExpression>(message, paramRefIdent, lexer::TokenType::PUNCTUATOR_PLUS); 574 575 paramRefIdent->SetParent(newExprArg); 576 ArenaVector<ir::Expression *> newExprArgs(checker->Allocator()->Adapter()); 577 newExprArgs.push_back(newExprArg); 578 579 auto *const exceptionReference = MakeTypeReference(checker, "Exception"); 580 auto *const newExpr = 581 checker->AllocNode<ir::ETSNewClassInstanceExpression>(exceptionReference, std::move(newExprArgs), nullptr); 582 return checker->AllocNode<ir::ThrowStatement>(newExpr); 583} 584 585ir::ReturnStatement *CreateReturnWitAsStatement(EnumLoweringPhase *const elp, ir::Identifier *const arrayIdentifier, 586 ir::ETSParameterExpression *const parameter) 587{ 588 auto *const checker = elp->Checker(); 589 auto *const paramRefIdent = MakeParamRefIdent(checker, parameter); 590 auto intType = checker->AllocNode<ir::ETSPrimitiveType>(ir::PrimitiveType::INT); 591 auto asExpression = checker->AllocNode<ir::TSAsExpression>(paramRefIdent, intType, false); 592 paramRefIdent->SetParent(asExpression); 593 594 auto *const arrayAccessExpr = checker->AllocNode<ir::MemberExpression>( 595 arrayIdentifier, asExpression, ir::MemberExpressionKind::ELEMENT_ACCESS, true, false); 596 597 return checker->AllocNode<ir::ReturnStatement>(arrayAccessExpr); 598} 599 600} // namespace 601 602void EnumLoweringPhase::CreateEnumFromIntMethod(const ir::TSEnumDeclaration *const enumDecl, 603 ir::ClassDefinition *const enumClass, ir::Identifier *const arrayIdent, 604 const util::StringView &methodName, 605 const util::StringView &returnTypeName) 606{ 607 auto *const paramScope = 608 varbinder_->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), enumClass->Scope()); 609 610 auto *const intTypeAnnotation = checker_->AllocNode<ir::ETSPrimitiveType>(ir::PrimitiveType::INT); 611 auto *const inputOrdinalParameter = 612 MakeFunctionParam(checker_, varbinder_, paramScope, "ordinal", intTypeAnnotation); 613 auto *const inArraySizeExpr = CreateIfTest(this, arrayIdent, inputOrdinalParameter); 614 auto *const returnEnumStmt = CreateReturnEnumStatement(this, arrayIdent, inputOrdinalParameter); 615 auto *const ifOrdinalExistsStmt = checker_->AllocNode<ir::IfStatement>(inArraySizeExpr, returnEnumStmt, nullptr); 616 617 util::UString messageString(util::StringView("No enum constant in "), Allocator()); 618 messageString.Append(enumDecl->Key()->Name()); 619 messageString.Append(" with ordinal value "); 620 621 auto *const throwNoEnumStmt = CreateThrowStatement(this, inputOrdinalParameter, messageString); 622 623 ArenaVector<ir::Expression *> params(Allocator()->Adapter()); 624 params.push_back(inputOrdinalParameter); 625 626 ArenaVector<ir::Statement *> body(Allocator()->Adapter()); 627 body.push_back(ifOrdinalExistsStmt); 628 body.push_back(throwNoEnumStmt); 629 auto *const returnTypeAnnotation = MakeTypeReference(checker_, returnTypeName); 630 631 auto *const function = MakeFunction({paramScope, std::move(params), std::move(body), returnTypeAnnotation, enumDecl, 632 ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC}); 633 function->AddFlag(ir::ScriptFunctionFlags::THROWS); 634 auto *const ident = checker_->AllocNode<ir::Identifier>(methodName, Allocator()); 635 636 function->SetIdent(ident); 637 function->Scope()->BindInternalName(ident->Name()); 638 639 MakeMethodDef(checker_, enumClass, varbinder_, ident, function); 640 ident->SetReference(); 641} 642 643void EnumLoweringPhase::CreateEnumToStringMethod(const ir::TSEnumDeclaration *const enumDecl, 644 ir::ClassDefinition *const enumClass, 645 ir::Identifier *const stringValuesArrayIdent) 646{ 647 auto *const paramScope = 648 varbinder_->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), enumClass->Scope()); 649 auto *const enumTypeAnnotation = MakeTypeReference(checker_, enumDecl->Key()->Name()); 650 auto *const inputEnumIdent = MakeFunctionParam(checker_, varbinder_, paramScope, "ordinal", enumTypeAnnotation); 651 auto *const returnStmt = CreateReturnWitAsStatement(this, stringValuesArrayIdent, inputEnumIdent); 652 653 ArenaVector<ir::Statement *> body(Allocator()->Adapter()); 654 body.push_back(returnStmt); 655 656 ArenaVector<ir::Expression *> params(Allocator()->Adapter()); 657 params.push_back(inputEnumIdent); 658 auto *const stringTypeAnnotation = MakeTypeReference(checker_, "String"); // NOTE String -> Builtin? 659 auto *const function = MakeFunction({paramScope, std::move(params), std::move(body), stringTypeAnnotation, enumDecl, 660 ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC}); 661 662 auto *const functionIdent = 663 checker_->AllocNode<ir::Identifier>(checker::ETSEnumType::TO_STRING_METHOD_NAME, Allocator()); 664 665 function->SetIdent(functionIdent); 666 function->Scope()->BindInternalName(functionIdent->Name()); 667 MakeMethodDef(checker_, enumClass, varbinder_, functionIdent, function); 668 functionIdent->SetReference(); 669} 670 671void EnumLoweringPhase::CreateEnumValueOfMethod(const ir::TSEnumDeclaration *const enumDecl, 672 ir::ClassDefinition *const enumClass, 673 ir::Identifier *const valuesArrayIdent) 674{ 675 auto *const paramScope = 676 varbinder_->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), enumClass->Scope()); 677 678 auto *const enumTypeAnnotation = MakeTypeReference(checker_, enumDecl->Key()->Name()); 679 auto *const inputEnumIdent = MakeFunctionParam(checker_, varbinder_, paramScope, "e", enumTypeAnnotation); 680 auto *const returnStmt = CreateReturnWitAsStatement(this, valuesArrayIdent, inputEnumIdent); 681 682 ArenaVector<ir::Statement *> body(Allocator()->Adapter()); 683 body.push_back(returnStmt); 684 685 ArenaVector<ir::Expression *> params(Allocator()->Adapter()); 686 params.push_back(inputEnumIdent); 687 auto *const intTypeAnnotation = checker_->AllocNode<ir::ETSPrimitiveType>(ir::PrimitiveType::INT); 688 auto *const function = MakeFunction({paramScope, std::move(params), std::move(body), intTypeAnnotation, enumDecl, 689 ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC}); 690 auto *const functionIdent = 691 checker_->AllocNode<ir::Identifier>(checker::ETSEnumType::VALUE_OF_METHOD_NAME, Allocator()); 692 function->SetIdent(functionIdent); 693 function->Scope()->BindInternalName(functionIdent->Name()); 694 695 MakeMethodDef(checker_, enumClass, varbinder_, functionIdent, function); 696 697 functionIdent->SetReference(); 698} 699 700void EnumLoweringPhase::CreateEnumGetNameMethod(const ir::TSEnumDeclaration *const enumDecl, 701 ir::ClassDefinition *const enumClass, 702 ir::Identifier *const namesArrayIdent) 703{ 704 auto *const paramScope = 705 varbinder_->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), enumClass->Scope()); 706 707 auto *const enumTypeAnnotation = MakeTypeReference(checker_, enumDecl->Key()->Name()); 708 auto *const inputEnumIdent = MakeFunctionParam(checker_, varbinder_, paramScope, "ordinal", enumTypeAnnotation); 709 auto *const returnStmt = CreateReturnWitAsStatement(this, namesArrayIdent, inputEnumIdent); 710 711 ArenaVector<ir::Statement *> body(Allocator()->Adapter()); 712 body.push_back(returnStmt); 713 714 ArenaVector<ir::Expression *> params(Allocator()->Adapter()); 715 params.push_back(inputEnumIdent); 716 auto *const stringTypeAnnotation = MakeTypeReference(checker_, "String"); // NOTE String -> Builtin? 717 718 auto *const function = MakeFunction({paramScope, std::move(params), std::move(body), stringTypeAnnotation, enumDecl, 719 ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC}); 720 auto *const functionIdent = 721 checker_->AllocNode<ir::Identifier>(checker::ETSEnumType::GET_NAME_METHOD_NAME, Allocator()); 722 723 function->SetIdent(functionIdent); 724 function->Scope()->BindInternalName(functionIdent->Name()); 725 726 MakeMethodDef(checker_, enumClass, varbinder_, functionIdent, function); 727 functionIdent->SetReference(); 728} 729 730namespace { 731 732ir::Identifier *CreateForLoopIdent(EnumLoweringPhase *const elp) 733{ 734 auto *const ident = elp->Checker()->AllocNode<ir::Identifier>("i", elp->Checker()->Allocator()); 735 auto [decl, var] = elp->Varbinder()->NewVarDecl<varbinder::LetDecl>(ident->Start(), ident->Name()); 736 ident->SetVariable(var); 737 var->SetScope(elp->Varbinder()->GetScope()); 738 var->AddFlag(varbinder::VariableFlags::LOCAL); 739 decl->BindNode(ident); 740 return ident; 741} 742 743ir::VariableDeclaration *CreateForLoopInitVariableDeclaration(EnumLoweringPhase *const elp, 744 ir::Identifier *const loopIdentifier) 745{ 746 auto *const checker = elp->Checker(); 747 auto *const init = checker->AllocNode<ir::NumberLiteral>("0"); 748 auto *const decl = 749 checker->AllocNode<ir::VariableDeclarator>(ir::VariableDeclaratorFlag::LET, loopIdentifier, init); 750 loopIdentifier->SetParent(decl); 751 ArenaVector<ir::VariableDeclarator *> decls(checker->Allocator()->Adapter()); 752 decls.push_back(decl); 753 auto *const declaration = checker->AllocNode<ir::VariableDeclaration>( 754 ir::VariableDeclaration::VariableDeclarationKind::LET, checker->Allocator(), std::move(decls), false); 755 decl->SetParent(declaration); 756 return declaration; 757} 758 759ir::BinaryExpression *CreateForLoopTest(EnumLoweringPhase *const elp, ir::Identifier *const namesArrayIdentifier, 760 ir::Identifier *const loopIdentifier) 761{ 762 auto *const checker = elp->Checker(); 763 auto *const lengthIdent = checker->AllocNode<ir::Identifier>("length", checker->Allocator()); 764 lengthIdent->SetReference(); 765 auto *const arrayLengthExpr = checker->AllocNode<ir::MemberExpression>( 766 namesArrayIdentifier, lengthIdent, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); 767 auto *const forLoopIdentClone = loopIdentifier->Clone(checker->Allocator(), nullptr); 768 auto *const binaryExpr = checker->AllocNode<ir::BinaryExpression>(forLoopIdentClone, arrayLengthExpr, 769 lexer::TokenType::PUNCTUATOR_LESS_THAN); 770 return binaryExpr; 771} 772 773ir::UpdateExpression *CreateForLoopUpdate(EnumLoweringPhase *const elp, ir::Identifier *const loopIdentifier) 774{ 775 auto *const checker = elp->Checker(); 776 auto *const forLoopIdentClone = loopIdentifier->Clone(checker->Allocator(), nullptr); 777 auto *const incrementExpr = 778 checker->AllocNode<ir::UpdateExpression>(forLoopIdentClone, lexer::TokenType::PUNCTUATOR_PLUS_PLUS, true); 779 return incrementExpr; 780} 781 782ir::IfStatement *CreateIf(EnumLoweringPhase *const elp, const ir::TSEnumDeclaration *const enumDecl, 783 ir::Identifier *const namesArrayIdentifier, ir::Identifier *const loopIdentifier, 784 ir::ETSParameterExpression *const parameter) 785{ 786 auto *const checker = elp->Checker(); 787 auto *const identClone = namesArrayIdentifier->Clone(checker->Allocator(), nullptr); 788 auto *const forLoopIdentClone1 = loopIdentifier->Clone(checker->Allocator(), nullptr); 789 auto *const namesArrayElementExpr = checker->AllocNode<ir::MemberExpression>( 790 identClone, forLoopIdentClone1, ir::MemberExpressionKind::ELEMENT_ACCESS, true, false); 791 792 auto *const paramRefIdent = MakeParamRefIdent(checker, parameter); 793 auto *const namesEqualExpr = checker->AllocNode<ir::BinaryExpression>(paramRefIdent, namesArrayElementExpr, 794 lexer::TokenType::PUNCTUATOR_EQUAL); 795 paramRefIdent->SetParent(namesEqualExpr); 796 auto *const forLoopIdentClone2 = loopIdentifier->Clone(checker->Allocator(), nullptr); 797 auto *const enumTypeAnnotation = MakeTypeReference(checker, enumDecl->Key()->Name()); 798 auto asExpression = checker->AllocNode<ir::TSAsExpression>(forLoopIdentClone2, enumTypeAnnotation, false); 799 800 auto *const returnStmt = checker->AllocNode<ir::ReturnStatement>(asExpression); 801 return checker->AllocNode<ir::IfStatement>(namesEqualExpr, returnStmt, nullptr); 802} 803 804} // namespace 805 806void EnumLoweringPhase::CreateEnumGetValueOfMethod(const ir::TSEnumDeclaration *const enumDecl, 807 ir::ClassDefinition *const enumClass, 808 ir::Identifier *const namesArrayIdent) 809{ 810 auto *const paramScope = 811 varbinder_->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), enumClass->Scope()); 812 813 varbinder::LexicalScope<varbinder::LoopDeclarationScope> loopDeclScope(varbinder_); 814 815 auto *const forLoopIIdent = CreateForLoopIdent(this); 816 auto *const forLoopInitVarDecl = CreateForLoopInitVariableDeclaration(this, forLoopIIdent); 817 auto *const forLoopTest = CreateForLoopTest(this, namesArrayIdent, forLoopIIdent); 818 auto *const forLoopUpdate = CreateForLoopUpdate(this, forLoopIIdent); 819 auto *const stringTypeAnnotation = MakeTypeReference(checker_, "String"); // NOTE String -> Builtin? 820 auto *const inputNameIdent = MakeFunctionParam(checker_, varbinder_, paramScope, "name", stringTypeAnnotation); 821 auto *const ifStmt = CreateIf(this, enumDecl, namesArrayIdent, forLoopIIdent, inputNameIdent); 822 823 varbinder::LexicalScope<varbinder::LoopScope> loopScope(varbinder_); 824 loopScope.GetScope()->BindDecls(loopDeclScope.GetScope()); 825 auto *const forLoop = 826 checker_->AllocNode<ir::ForUpdateStatement>(forLoopInitVarDecl, forLoopTest, forLoopUpdate, ifStmt); 827 loopScope.GetScope()->BindNode(forLoop); 828 forLoop->SetScope(loopScope.GetScope()); 829 loopScope.GetScope()->DeclScope()->BindNode(forLoop); 830 831 util::UString messageString(util::StringView("No enum constant "), Allocator()); 832 messageString.Append(enumDecl->Key()->Name()); 833 messageString.Append('.'); 834 835 auto *const throwStmt = CreateThrowStatement(this, inputNameIdent, messageString); 836 837 ArenaVector<ir::Statement *> body(Allocator()->Adapter()); 838 body.push_back(forLoop); 839 body.push_back(throwStmt); 840 841 ArenaVector<ir::Expression *> params(Allocator()->Adapter()); 842 params.push_back(inputNameIdent); 843 auto *const enumTypeAnnotation = MakeTypeReference(checker_, enumDecl->Key()->Name()); 844 845 auto *const function = MakeFunction({paramScope, std::move(params), std::move(body), enumTypeAnnotation, enumDecl, 846 ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC}); 847 function->AddFlag(ir::ScriptFunctionFlags::THROWS); 848 auto *const functionIdent = 849 checker_->AllocNode<ir::Identifier>(checker::ETSEnumType::GET_VALUE_OF_METHOD_NAME, Allocator()); 850 851 function->SetIdent(functionIdent); 852 function->Scope()->BindInternalName(functionIdent->Name()); 853 MakeMethodDef(checker_, enumClass, varbinder_, functionIdent, function); 854 functionIdent->SetReference(); 855} 856 857void EnumLoweringPhase::CreateEnumValuesMethod(const ir::TSEnumDeclaration *const enumDecl, 858 ir::ClassDefinition *const enumClass, 859 ir::Identifier *const itemsArrayIdent) 860{ 861 auto *const paramScope = 862 varbinder_->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), enumClass->Scope()); 863 auto *const returnStmt = checker_->AllocNode<ir::ReturnStatement>(itemsArrayIdent); 864 ArenaVector<ir::Statement *> body(Allocator()->Adapter()); 865 body.push_back(returnStmt); 866 867 ArenaVector<ir::Expression *> params(Allocator()->Adapter()); 868 auto *const enumArrayTypeAnnotation = 869 checker_->AllocNode<ir::TSArrayType>(MakeTypeReference(checker_, enumDecl->Key()->Name())); 870 871 auto *const function = MakeFunction({paramScope, std::move(params), std::move(body), enumArrayTypeAnnotation, 872 enumDecl, ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC}); 873 auto *const functionIdent = 874 checker_->AllocNode<ir::Identifier>(checker::ETSEnumType::VALUES_METHOD_NAME, Allocator()); 875 function->SetIdent(functionIdent); 876 function->Scope()->BindInternalName(functionIdent->Name()); 877 878 MakeMethodDef(checker_, enumClass, varbinder_, functionIdent, function); 879 functionIdent->SetReference(); 880} 881 882void EnumLoweringPhase::CreateUnboxingMethod(ir::TSEnumDeclaration const *const enumDecl, 883 ir::ClassDefinition *const enumClass, 884 ir::Identifier *const itemsArrayIdent) 885 886{ 887 auto *const paramScope = 888 varbinder_->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), enumClass->Scope()); 889 890 ArenaVector<ir::Statement *> body(Allocator()->Adapter()); 891 892 auto *thisExpr = Allocator()->New<ir::ThisExpression>(); 893 auto *fieldIdentifier = Allocator()->New<ir::Identifier>("ordinal", Allocator()); 894 fieldIdentifier->SetReference(); 895 auto *arrayIndexExpr = checker_->AllocNode<ir::MemberExpression>( 896 thisExpr, fieldIdentifier, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); 897 898 auto itemsArrayIdentClone = itemsArrayIdent->Clone(checker_->Allocator(), nullptr); 899 auto *const arrayAccessExpr = checker_->AllocNode<ir::MemberExpression>( 900 itemsArrayIdentClone, arrayIndexExpr, ir::MemberExpressionKind::ELEMENT_ACCESS, true, false); 901 902 auto *const returnStmt = checker_->AllocNode<ir::ReturnStatement>(arrayAccessExpr); 903 body.push_back(returnStmt); 904 905 ArenaVector<ir::Expression *> params(Allocator()->Adapter()); 906 907 auto *const returnTypeAnnotation = MakeTypeReference(checker_, enumDecl->Key()->Name()); 908 909 auto *const function = MakeFunction( 910 {paramScope, std::move(params), std::move(body), returnTypeAnnotation, enumDecl, ir::ModifierFlags::PUBLIC}); 911 912 varbinder_->AddFunctionThisParam(function); 913 auto *const functionIdent = 914 checker_->AllocNode<ir::Identifier>(checker::ETSEnumType::UNBOX_METHOD_NAME, Allocator()); 915 function->SetIdent(functionIdent); 916 function->Scope()->BindInternalName(functionIdent->Name()); 917 918 MakeMethodDef(checker_, enumClass, varbinder_, functionIdent, function); 919 functionIdent->SetReference(); 920} 921 922ArenaAllocator *EnumLoweringPhase::Allocator() 923{ 924 return checker_->Allocator(); 925} 926 927} // namespace ark::es2panda::compiler