• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "varbinder/ETSBinder.h"
17 #include "varbinder/variable.h"
18 #include "checker/ETSchecker.h"
19 #include "ir/base/classProperty.h"
20 #include "ir/base/methodDefinition.h"
21 #include "ir/base/property.h"
22 #include "ir/base/scriptFunction.h"
23 #include "ir/ets/etsNewClassInstanceExpression.h"
24 #include "ir/ets/etsPrimitiveType.h"
25 #include "ir/ets/etsTypeReference.h"
26 #include "ir/ets/etsTypeReferencePart.h"
27 #include "ir/expressions/arrayExpression.h"
28 #include "ir/expressions/binaryExpression.h"
29 #include "ir/expressions/functionExpression.h"
30 #include "ir/expressions/identifier.h"
31 #include "ir/expressions/literals/numberLiteral.h"
32 #include "ir/expressions/literals/stringLiteral.h"
33 #include "ir/expressions/memberExpression.h"
34 #include "ir/expressions/updateExpression.h"
35 #include "ir/statements/blockStatement.h"
36 #include "ir/statements/forUpdateStatement.h"
37 #include "ir/statements/ifStatement.h"
38 #include "ir/statements/returnStatement.h"
39 #include "ir/statements/throwStatement.h"
40 #include "ir/statements/variableDeclaration.h"
41 #include "ir/statements/variableDeclarator.h"
42 #include "ir/ts/tsArrayType.h"
43 #include "ir/ts/tsAsExpression.h"
44 #include "ir/ts/tsEnumMember.h"
45 #include "ir/ts/tsInterfaceBody.h"
46 #include "parser/program/program.h"
47 #include "ir/ets/etsParameterExpression.h"
48 
49 namespace panda::es2panda::checker {
50 
51 namespace {
AppendParentNames(util::UString & qualifiedName,const ir::AstNode * const node)52 void AppendParentNames(util::UString &qualifiedName, const ir::AstNode *const node)
53 {
54     if (node != nullptr && !node->IsProgram()) {
55         AppendParentNames(qualifiedName, node->Parent());
56         if (node->IsTSInterfaceDeclaration()) {
57             qualifiedName.Append(node->AsTSInterfaceDeclaration()->Id()->Name());
58         } else if (node->IsClassDefinition()) {
59             qualifiedName.Append(node->AsClassDefinition()->Ident()->Name());
60         } else {
61             ASSERT(node->IsClassDeclaration() || node->IsTSInterfaceBody());
62             return;
63         }
64         qualifiedName.Append('#');
65     }
66 }
67 
MakeQualifiedIdentifier(panda::ArenaAllocator * const allocator,const ir::TSEnumDeclaration * const enumDecl,const util::StringView & name)68 [[nodiscard]] ir::Identifier *MakeQualifiedIdentifier(panda::ArenaAllocator *const allocator,
69                                                       const ir::TSEnumDeclaration *const enumDecl,
70                                                       const util::StringView &name)
71 {
72     util::UString qualifiedName(util::StringView("#"), allocator);
73     AppendParentNames(qualifiedName, enumDecl->Parent());
74     qualifiedName.Append(enumDecl->Key()->Name());
75     qualifiedName.Append('#');
76     qualifiedName.Append(name);
77     return allocator->New<ir::Identifier>(qualifiedName.View(), allocator);
78 }
79 
80 template <typename ElementMaker>
MakeArray(ETSChecker * const checker,varbinder::ETSBinder * const varbinder,const ETSEnumInterface * const enumType,const util::StringView & name,Type * const elementType,ElementMaker && elementMaker)81 [[nodiscard]] ir::Identifier *MakeArray(ETSChecker *const checker, varbinder::ETSBinder *const varbinder,
82                                         const ETSEnumInterface *const enumType, const util::StringView &name,
83                                         Type *const elementType, ElementMaker &&elementMaker)
84 {
85     ArenaVector<ir::Expression *> elements(checker->Allocator()->Adapter());
86     elements.reserve(enumType->GetMembers().size());
87     for (const auto *const member : enumType->GetMembers()) {
88         elements.push_back(elementMaker(member->AsTSEnumMember()));
89     }
90 
91     auto *const arrayExpr = checker->Allocator()->New<ir::ArrayExpression>(std::move(elements), checker->Allocator());
92     arrayExpr->SetPreferredType(elementType);
93     arrayExpr->SetTsType(checker->CreateETSArrayType(elementType));
94 
95     auto *const arrayIdent = MakeQualifiedIdentifier(checker->Allocator(), enumType->GetDecl(), name);
96 
97     auto *const arrayClassProp = checker->Allocator()->New<ir::ClassProperty>(
98         arrayIdent, arrayExpr, nullptr,
99         ir::ModifierFlags::STATIC | ir::ModifierFlags::PUBLIC | ir::ModifierFlags::CONST, checker->Allocator(), false);
100     arrayClassProp->SetTsType(arrayExpr->TsType());
101     arrayClassProp->SetParent(varbinder->Program()->GlobalClass());
102     arrayIdent->SetTsType(arrayClassProp->TsType());
103     varbinder->Program()->GlobalClass()->Body().push_back(arrayClassProp);
104 
105     auto [array_decl, array_var] =
106         varbinder->NewVarDecl<varbinder::ConstDecl>(arrayIdent->Start(), arrayIdent->Name(), arrayClassProp);
107     arrayIdent->SetVariable(array_var);
108     array_var->SetTsType(arrayClassProp->TsType());
109     array_var->AddFlag(varbinder::VariableFlags::PUBLIC | varbinder::VariableFlags::STATIC |
110                        varbinder::VariableFlags::PROPERTY);
111     array_decl->Node()->SetParent(varbinder->Program()->GlobalClass());
112     return arrayIdent;
113 }
114 
MakeFunctionParam(ETSChecker * const checker,varbinder::ETSBinder * const varbinder,varbinder::FunctionParamScope * const scope,const util::StringView & name,Type * const type)115 [[nodiscard]] ir::ETSParameterExpression *MakeFunctionParam(ETSChecker *const checker,
116                                                             varbinder::ETSBinder *const varbinder,
117                                                             varbinder::FunctionParamScope *const scope,
118                                                             const util::StringView &name, Type *const type)
119 {
120     const auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(varbinder, scope, false);
121     auto *const paramIdent = checker->Allocator()->New<ir::Identifier>(name, checker->Allocator());
122     auto *const param = checker->Allocator()->New<ir::ETSParameterExpression>(paramIdent, nullptr);
123     auto *const paramVar = std::get<1>(varbinder->AddParamDecl(param));
124     paramVar->SetTsType(type);
125     param->Ident()->SetVariable(paramVar);
126     param->Ident()->SetTsType(type);
127     param->SetTsType(type);
128     return param;
129 }
130 
MakeTypeReference(panda::ArenaAllocator * allocator,const util::StringView & name)131 [[nodiscard]] ir::ETSTypeReference *MakeTypeReference(panda::ArenaAllocator *allocator, const util::StringView &name)
132 {
133     auto *const ident = allocator->New<ir::Identifier>(name, allocator);
134     auto *const referencePart = allocator->New<ir::ETSTypeReferencePart>(ident);
135     return allocator->New<ir::ETSTypeReference>(referencePart);
136 }
137 
MakeFunction(ETSChecker * const checker,varbinder::ETSBinder * const varbinder,varbinder::FunctionParamScope * const paramScope,ArenaVector<ir::Expression * > && params,ArenaVector<ir::Statement * > && body,ir::TypeNode * const returnTypeAnnotation,bool isDeclare)138 [[nodiscard]] ir::ScriptFunction *MakeFunction(ETSChecker *const checker, varbinder::ETSBinder *const varbinder,
139                                                varbinder::FunctionParamScope *const paramScope,
140                                                ArenaVector<ir::Expression *> &&params,
141                                                ArenaVector<ir::Statement *> &&body,
142                                                ir::TypeNode *const returnTypeAnnotation, bool isDeclare)
143 {
144     auto *const functionScope = varbinder->Allocator()->New<varbinder::FunctionScope>(checker->Allocator(), paramScope);
145     functionScope->BindParamScope(paramScope);
146     paramScope->BindFunctionScope(functionScope);
147 
148     auto *const bodyBlock = checker->Allocator()->New<ir::BlockStatement>(checker->Allocator(), std::move(body));
149     bodyBlock->SetScope(functionScope);
150 
151     auto flags = ir::ModifierFlags::PUBLIC;
152 
153     if (isDeclare) {
154         flags |= ir::ModifierFlags::DECLARE;
155     }
156 
157     auto *const function = checker->Allocator()->New<ir::ScriptFunction>(
158         ir::FunctionSignature(nullptr, std::move(params), returnTypeAnnotation), bodyBlock,
159         ir::ScriptFunctionFlags::METHOD, flags, isDeclare, Language(Language::Id::ETS));
160     function->SetScope(functionScope);
161 
162     varbinder->AsETSBinder()->BuildInternalName(function);
163     varbinder->AsETSBinder()->AddCompilableFunction(function);
164     paramScope->BindNode(function);
165     functionScope->BindNode(function);
166 
167     return function;
168 }
169 
MakeMethodDef(ETSChecker * const checker,varbinder::ETSBinder * const varbinder,ir::Identifier * const ident,ir::ScriptFunction * const function)170 void MakeMethodDef(ETSChecker *const checker, varbinder::ETSBinder *const varbinder, ir::Identifier *const ident,
171                    ir::ScriptFunction *const function)
172 {
173     auto *const functionExpr = checker->Allocator()->New<ir::FunctionExpression>(function);
174     function->SetParent(functionExpr);
175 
176     auto *const methodDef = checker->Allocator()->New<ir::MethodDefinition>(
177         ir::MethodDefinitionKind::METHOD, ident, functionExpr, ir::ModifierFlags::PUBLIC, checker->Allocator(), false);
178     methodDef->SetParent(varbinder->Program()->GlobalClass());
179     functionExpr->SetParent(methodDef);
180 
181     auto *const methodVar = std::get<1>(varbinder->NewVarDecl<varbinder::FunctionDecl>(
182         methodDef->Start(), checker->Allocator(), methodDef->Id()->Name(), methodDef));
183     methodVar->AddFlag(varbinder::VariableFlags::STATIC | varbinder::VariableFlags::SYNTHETIC |
184                        varbinder::VariableFlags::METHOD);
185     methodDef->Function()->Id()->SetVariable(methodVar);
186 }
187 
MakeProxyFunctionType(ETSChecker * const checker,const util::StringView & name,const std::initializer_list<varbinder::LocalVariable * > & params,ir::ScriptFunction * const globalFunction,Type * const returnType)188 [[nodiscard]] ETSFunctionType *MakeProxyFunctionType(ETSChecker *const checker, const util::StringView &name,
189                                                      const std::initializer_list<varbinder::LocalVariable *> &params,
190                                                      ir::ScriptFunction *const globalFunction, Type *const returnType)
191 {
192     auto *const signatureInfo = checker->CreateSignatureInfo();
193     signatureInfo->params.insert(signatureInfo->params.end(), params);
194     signatureInfo->minArgCount = signatureInfo->params.size();
195 
196     auto *const signature = checker->CreateSignature(signatureInfo, returnType, name);
197     signature->SetFunction(globalFunction);
198     signature->AddSignatureFlag(SignatureFlags::PROXY);
199 
200     return checker->CreateETSFunctionType(signature, name);
201 }
202 
MakeGlobalSignature(ETSChecker * const checker,ir::ScriptFunction * const function,Type * const returnType)203 [[nodiscard]] Signature *MakeGlobalSignature(ETSChecker *const checker, ir::ScriptFunction *const function,
204                                              Type *const returnType)
205 {
206     auto *const signatureInfo = checker->CreateSignatureInfo();
207     signatureInfo->params.reserve(function->Params().size());
208     for (const auto *const param : function->Params()) {
209         signatureInfo->params.push_back(param->AsETSParameterExpression()->Variable()->AsLocalVariable());
210     }
211     signatureInfo->minArgCount = signatureInfo->params.size();
212 
213     auto *const signature = checker->CreateSignature(signatureInfo, returnType, function);
214     signature->AddSignatureFlag(SignatureFlags::PUBLIC | SignatureFlags::STATIC);
215     function->SetSignature(signature);
216 
217     return signature;
218 }
219 }  // namespace
220 
CreateEnumNamesArray(ETSEnumInterface const * const enumType)221 ir::Identifier *ETSChecker::CreateEnumNamesArray(ETSEnumInterface const *const enumType)
222 {
223     // clang-format off
224     return MakeArray(this, VarBinder()->AsETSBinder(), enumType, "NamesArray", GlobalBuiltinETSStringType(),
225                     [this](const ir::TSEnumMember *const member) {
226                         auto *const enumNameStringLiteral =
227                             Allocator()->New<ir::StringLiteral>(member->Key()->AsIdentifier()->Name());
228                         enumNameStringLiteral->SetTsType(GlobalBuiltinETSStringType());
229                         return enumNameStringLiteral;
230                     });
231     // clang-format on
232 }
233 
CreateEnumValuesArray(ETSEnumType * const enumType)234 ir::Identifier *ETSChecker::CreateEnumValuesArray(ETSEnumType *const enumType)
235 {
236     return MakeArray(
237         this, VarBinder()->AsETSBinder(), enumType, "ValuesArray", GlobalIntType(),
238         [this](const ir::TSEnumMember *const member) {
239             auto *const enumValueLiteral = Allocator()->New<ir::NumberLiteral>(lexer::Number(
240                 member->AsTSEnumMember()->Init()->AsNumberLiteral()->Number().GetValue<ETSEnumType::ValueType>()));
241             enumValueLiteral->SetTsType(GlobalIntType());
242             return enumValueLiteral;
243         });
244 }
245 
CreateEnumStringValuesArray(ETSEnumInterface * const enumType)246 ir::Identifier *ETSChecker::CreateEnumStringValuesArray(ETSEnumInterface *const enumType)
247 {
248     return MakeArray(this, VarBinder()->AsETSBinder(), enumType, "StringValuesArray", GlobalETSStringLiteralType(),
249                      [this, isStringEnum = enumType->IsETSStringEnumType()](const ir::TSEnumMember *const member) {
250                          auto const stringValue =
251                              isStringEnum ? member->AsTSEnumMember()->Init()->AsStringLiteral()->Str()
252                                           : util::UString(std::to_string(member->AsTSEnumMember()
253                                                                              ->Init()
254                                                                              ->AsNumberLiteral()
255                                                                              ->Number()
256                                                                              .GetValue<ETSEnumType::ValueType>()),
257                                                           Allocator())
258                                                 .View();
259                          auto *const enumValueStringLiteral = Allocator()->New<ir::StringLiteral>(stringValue);
260                          enumValueStringLiteral->SetTsType(GlobalETSStringLiteralType());
261                          return enumValueStringLiteral;
262                      });
263 }
264 
CreateEnumItemsArray(ETSEnumInterface * const enumType)265 ir::Identifier *ETSChecker::CreateEnumItemsArray(ETSEnumInterface *const enumType)
266 {
267     auto *const enumTypeIdent = Allocator()->New<ir::Identifier>(enumType->GetName(), Allocator());
268     enumTypeIdent->SetTsType(enumType);
269 
270     return MakeArray(
271         this, VarBinder()->AsETSBinder(), enumType, "ItemsArray", enumType,
272         [this, enumTypeIdent](const ir::TSEnumMember *const member) {
273             auto *const enumMemberIdent =
274                 Allocator()->New<ir::Identifier>(member->AsTSEnumMember()->Key()->AsIdentifier()->Name(), Allocator());
275             auto *const enumMemberExpr = Allocator()->New<ir::MemberExpression>(
276                 enumTypeIdent, enumMemberIdent, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
277             enumMemberExpr->SetTsType(member->AsTSEnumMember()->Key()->AsIdentifier()->Variable()->TsType());
278             return enumMemberExpr;
279         });
280 }
281 
CreateEnumFromIntMethod(ir::Identifier * const namesArrayIdent,ETSEnumInterface * const enumType)282 ETSEnumType::Method ETSChecker::CreateEnumFromIntMethod(ir::Identifier *const namesArrayIdent,
283                                                         ETSEnumInterface *const enumType)
284 {
285     auto *const paramScope =
286         VarBinder()->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), Program()->GlobalScope());
287 
288     auto *const inputOrdinalIdent =
289         MakeFunctionParam(this, VarBinder()->AsETSBinder(), paramScope, "ordinal", GlobalIntType());
290 
291     auto *const inArraySizeExpr = [this, namesArrayIdent, inputOrdinalIdent]() {
292         auto *const lengthIdent = Allocator()->New<ir::Identifier>("length", Allocator());
293         auto *const valuesArrayLengthExpr = Allocator()->New<ir::MemberExpression>(
294             namesArrayIdent, lengthIdent, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
295         auto *const expr = Allocator()->New<ir::BinaryExpression>(inputOrdinalIdent, valuesArrayLengthExpr,
296                                                                   lexer::TokenType::PUNCTUATOR_LESS_THAN);
297         expr->SetOperationType(GlobalIntType());
298         expr->SetTsType(GlobalETSBooleanType());
299         return expr;
300     }();
301 
302     auto *const returnEnumStmt = [this, inputOrdinalIdent, enumType]() {
303         inputOrdinalIdent->SetTsType(enumType);
304         return Allocator()->New<ir::ReturnStatement>(inputOrdinalIdent);
305     }();
306 
307     auto *const ifOrdinalExistsStmt = Allocator()->New<ir::IfStatement>(inArraySizeExpr, returnEnumStmt, nullptr);
308 
309     auto *const throwNoEnumStmt = [this, inputOrdinalIdent, enumType]() {
310         auto *const exceptionReference = MakeTypeReference(Allocator(), "Exception");
311 
312         util::UString messageString(util::StringView("No enum constant in "), Allocator());
313         messageString.Append(enumType->GetName());
314         messageString.Append(" with ordinal value ");
315 
316         auto *const message = Allocator()->New<ir::StringLiteral>(messageString.View());
317         auto *const newExprArg =
318             Allocator()->New<ir::BinaryExpression>(message, inputOrdinalIdent, lexer::TokenType::PUNCTUATOR_PLUS);
319         ArenaVector<ir::Expression *> newExprArgs(Allocator()->Adapter());
320         newExprArgs.push_back(newExprArg);
321 
322         auto *const newExpr = Allocator()->New<ir::ETSNewClassInstanceExpression>(
323             exceptionReference, std::move(newExprArgs),
324             GlobalBuiltinExceptionType()->GetDeclNode()->AsClassDefinition());
325 
326         newExpr->SetSignature(
327             ResolveConstructExpression(GlobalBuiltinExceptionType(), newExpr->GetArguments(), newExpr->Start()));
328         newExpr->SetTsType(GlobalBuiltinExceptionType());
329 
330         return Allocator()->New<ir::ThrowStatement>(newExpr);
331     }();
332 
333     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
334     params.push_back(inputOrdinalIdent);
335 
336     ArenaVector<ir::Statement *> body(Allocator()->Adapter());
337     body.push_back(ifOrdinalExistsStmt);
338     body.push_back(throwNoEnumStmt);
339     body.push_back(returnEnumStmt);
340 
341     auto *const enumTypeAnnotation = MakeTypeReference(Allocator(), enumType->GetName());
342 
343     auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params),
344                                         std::move(body), enumTypeAnnotation, enumType->GetDecl()->IsDeclare());
345     function->AddFlag(ir::ScriptFunctionFlags::THROWS);
346 
347     auto *const ident = MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::FROM_INT_METHOD_NAME);
348     function->SetIdent(ident);
349     function->Scope()->BindInternalName(ident->Name());
350 
351     MakeMethodDef(this, VarBinder()->AsETSBinder(), ident, function);
352 
353     return {MakeGlobalSignature(this, function, enumType), nullptr};
354 }
355 
CreateEnumToStringMethod(ir::Identifier * const stringValuesArrayIdent,ETSEnumInterface * const enumType)356 ETSEnumType::Method ETSChecker::CreateEnumToStringMethod(ir::Identifier *const stringValuesArrayIdent,
357                                                          ETSEnumInterface *const enumType)
358 {
359     auto *const paramScope =
360         VarBinder()->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), Program()->GlobalClassScope());
361 
362     auto *const inputEnumIdent = MakeFunctionParam(this, VarBinder()->AsETSBinder(), paramScope, "ordinal", enumType);
363 
364     auto *const returnStmt = [this, inputEnumIdent, stringValuesArrayIdent]() {
365         auto *const arrayAccessExpr = Allocator()->New<ir::MemberExpression>(
366             stringValuesArrayIdent, inputEnumIdent, ir::MemberExpressionKind::ELEMENT_ACCESS, true, false);
367         arrayAccessExpr->SetTsType(GlobalETSStringLiteralType());
368 
369         return Allocator()->New<ir::ReturnStatement>(arrayAccessExpr);
370     }();
371 
372     ArenaVector<ir::Statement *> body(Allocator()->Adapter());
373     body.push_back(returnStmt);
374 
375     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
376     params.push_back(inputEnumIdent);
377 
378     auto *const stringTypeAnnotation = MakeTypeReference(Allocator(), GlobalBuiltinETSStringType()->Name());
379     auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params),
380                                         std::move(body), stringTypeAnnotation, enumType->GetDecl()->IsDeclare());
381 
382     auto *const functionIdent =
383         MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::TO_STRING_METHOD_NAME);
384     function->SetIdent(functionIdent);
385     function->Scope()->BindInternalName(functionIdent->Name());
386 
387     MakeMethodDef(this, VarBinder()->AsETSBinder(), functionIdent, function);
388 
389     return {
390         MakeGlobalSignature(this, function, GlobalETSStringLiteralType()),
391         MakeProxyFunctionType(this, ETSEnumType::TO_STRING_METHOD_NAME, {}, function, GlobalETSStringLiteralType())};
392 }
393 
CreateEnumGetValueMethod(ir::Identifier * const valuesArrayIdent,ETSEnumType * const enumType)394 ETSEnumType::Method ETSChecker::CreateEnumGetValueMethod(ir::Identifier *const valuesArrayIdent,
395                                                          ETSEnumType *const enumType)
396 {
397     auto *const paramScope =
398         VarBinder()->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), Program()->GlobalClassScope());
399 
400     auto *const inputEnumIdent = MakeFunctionParam(this, VarBinder()->AsETSBinder(), paramScope, "e", enumType);
401 
402     auto *const returnStmt = [this, inputEnumIdent, valuesArrayIdent]() {
403         auto *const arrayAccessExpr = Allocator()->New<ir::MemberExpression>(
404             valuesArrayIdent, inputEnumIdent, ir::MemberExpressionKind::ELEMENT_ACCESS, true, false);
405         arrayAccessExpr->SetTsType(GlobalIntType());
406 
407         return Allocator()->New<ir::ReturnStatement>(arrayAccessExpr);
408     }();
409 
410     ArenaVector<ir::Statement *> body(Allocator()->Adapter());
411     body.push_back(returnStmt);
412 
413     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
414     params.push_back(inputEnumIdent);
415 
416     auto *const intTypeAnnotation = Allocator()->New<ir::ETSPrimitiveType>(ir::PrimitiveType::INT);
417     auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params),
418                                         std::move(body), intTypeAnnotation, enumType->GetDecl()->IsDeclare());
419 
420     auto *const functionIdent =
421         MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::GET_VALUE_METHOD_NAME);
422     function->SetIdent(functionIdent);
423     function->Scope()->BindInternalName(functionIdent->Name());
424 
425     MakeMethodDef(this, VarBinder()->AsETSBinder(), functionIdent, function);
426 
427     return {MakeGlobalSignature(this, function, GlobalIntType()),
428             MakeProxyFunctionType(this, ETSEnumType::GET_VALUE_METHOD_NAME, {}, function, GlobalIntType())};
429 }
430 
CreateEnumGetNameMethod(ir::Identifier * const namesArrayIdent,ETSEnumInterface * const enumType)431 ETSEnumType::Method ETSChecker::CreateEnumGetNameMethod(ir::Identifier *const namesArrayIdent,
432                                                         ETSEnumInterface *const enumType)
433 {
434     auto *const paramScope =
435         VarBinder()->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), Program()->GlobalScope());
436 
437     auto *const inputEnumIdent = MakeFunctionParam(this, VarBinder()->AsETSBinder(), paramScope, "ordinal", enumType);
438 
439     auto *const returnStmt = [this, inputEnumIdent, namesArrayIdent]() {
440         auto *const arrayAccessExpr = Allocator()->New<ir::MemberExpression>(
441             namesArrayIdent, inputEnumIdent, ir::MemberExpressionKind::ELEMENT_ACCESS, true, false);
442         arrayAccessExpr->SetTsType(GlobalBuiltinETSStringType());
443 
444         return Allocator()->New<ir::ReturnStatement>(arrayAccessExpr);
445     }();
446 
447     ArenaVector<ir::Statement *> body(Allocator()->Adapter());
448     body.push_back(returnStmt);
449 
450     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
451     params.push_back(inputEnumIdent);
452 
453     auto *const stringTypeAnnotation = MakeTypeReference(Allocator(), GlobalBuiltinETSStringType()->Name());
454 
455     auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params),
456                                         std::move(body), stringTypeAnnotation, enumType->GetDecl()->IsDeclare());
457 
458     auto *const functionIdent =
459         MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::GET_NAME_METHOD_NAME);
460     function->SetIdent(functionIdent);
461     function->Scope()->BindInternalName(functionIdent->Name());
462 
463     MakeMethodDef(this, VarBinder()->AsETSBinder(), functionIdent, function);
464 
465     return {MakeGlobalSignature(this, function, GlobalBuiltinETSStringType()),
466             MakeProxyFunctionType(this, ETSEnumType::GET_NAME_METHOD_NAME, {}, function, GlobalBuiltinETSStringType())};
467 }
468 
CreateEnumValueOfMethod(ir::Identifier * const namesArrayIdent,ETSEnumInterface * const enumType)469 ETSEnumType::Method ETSChecker::CreateEnumValueOfMethod(ir::Identifier *const namesArrayIdent,
470                                                         ETSEnumInterface *const enumType)
471 {
472     auto *const paramScope =
473         VarBinder()->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), Program()->GlobalScope());
474 
475     auto *const inputNameIdent =
476         MakeFunctionParam(this, VarBinder()->AsETSBinder(), paramScope, "name", GlobalBuiltinETSStringType());
477 
478     varbinder::LexicalScope<varbinder::LoopDeclarationScope> loopDeclScope(VarBinder());
479 
480     auto *const forLoopIIdent = [this]() {
481         auto *const ident = Allocator()->New<ir::Identifier>("i", Allocator());
482         ident->SetTsType(GlobalIntType());
483         auto [decl, var] = VarBinder()->NewVarDecl<varbinder::LetDecl>(ident->Start(), ident->Name());
484         ident->SetVariable(var);
485         var->SetTsType(GlobalIntType());
486         var->SetScope(VarBinder()->GetScope());
487         var->AddFlag(varbinder::VariableFlags::LOCAL);
488         decl->BindNode(ident);
489         return ident;
490     }();
491 
492     auto *const forLoopInitVarDecl = [this, forLoopIIdent]() {
493         auto *const init = Allocator()->New<ir::NumberLiteral>("0");
494         init->SetTsType(GlobalIntType());
495         auto *const decl =
496             Allocator()->New<ir::VariableDeclarator>(ir::VariableDeclaratorFlag::LET, forLoopIIdent, init);
497         decl->SetTsType(GlobalIntType());
498         ArenaVector<ir::VariableDeclarator *> decls(Allocator()->Adapter());
499         decls.push_back(decl);
500         return Allocator()->New<ir::VariableDeclaration>(ir::VariableDeclaration::VariableDeclarationKind::LET,
501                                                          Allocator(), std::move(decls), false);
502     }();
503 
504     auto *const forLoopTest = [this, namesArrayIdent, forLoopIIdent]() {
505         auto *const lengthIdent = Allocator()->New<ir::Identifier>("length", Allocator());
506         auto *const arrayLengthExpr = Allocator()->New<ir::MemberExpression>(
507             namesArrayIdent, lengthIdent, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
508         arrayLengthExpr->SetTsType(GlobalIntType());
509         auto *const binaryExpr = Allocator()->New<ir::BinaryExpression>(forLoopIIdent, arrayLengthExpr,
510                                                                         lexer::TokenType::PUNCTUATOR_LESS_THAN);
511         binaryExpr->SetOperationType(GlobalIntType());
512         binaryExpr->SetTsType(GlobalETSBooleanType());
513         return binaryExpr;
514     }();
515 
516     auto *const forLoopUpdate = [this, forLoopIIdent]() {
517         auto *const incrementExpr =
518             Allocator()->New<ir::UpdateExpression>(forLoopIIdent, lexer::TokenType::PUNCTUATOR_PLUS_PLUS, true);
519         incrementExpr->SetTsType(GlobalIntType());
520         return incrementExpr;
521     }();
522 
523     auto *const ifStmt = [this, namesArrayIdent, forLoopIIdent, inputNameIdent]() {
524         auto *const namesArrayElementExpr = Allocator()->New<ir::MemberExpression>(
525             namesArrayIdent, forLoopIIdent, ir::MemberExpressionKind::ELEMENT_ACCESS, true, false);
526         namesArrayElementExpr->SetTsType(GlobalBuiltinETSStringType());
527 
528         auto *const namesEqualExpr = Allocator()->New<ir::BinaryExpression>(inputNameIdent, namesArrayElementExpr,
529                                                                             lexer::TokenType::PUNCTUATOR_EQUAL);
530         namesEqualExpr->SetOperationType(GlobalBuiltinETSStringType());
531         namesEqualExpr->SetTsType(GlobalETSBooleanType());
532 
533         auto *const returnStmt = Allocator()->New<ir::ReturnStatement>(forLoopIIdent);
534         return Allocator()->New<ir::IfStatement>(namesEqualExpr, returnStmt, nullptr);
535     }();
536 
537     varbinder::LexicalScope<varbinder::LoopScope> loopScope(VarBinder());
538     loopScope.GetScope()->BindDecls(loopDeclScope.GetScope());
539 
540     auto *const forLoop =
541         Allocator()->New<ir::ForUpdateStatement>(forLoopInitVarDecl, forLoopTest, forLoopUpdate, ifStmt);
542     loopScope.GetScope()->BindNode(forLoop);
543     forLoop->SetScope(loopScope.GetScope());
544     loopScope.GetScope()->DeclScope()->BindNode(forLoop);
545 
546     auto *const throwStmt = [this, inputNameIdent, enumType]() {
547         util::UString messageString(util::StringView("No enum constant "), Allocator());
548         messageString.Append(enumType->GetName());
549         messageString.Append('.');
550 
551         auto *const message = Allocator()->New<ir::StringLiteral>(messageString.View());
552         auto *const newExprArg =
553             Allocator()->New<ir::BinaryExpression>(message, inputNameIdent, lexer::TokenType::PUNCTUATOR_PLUS);
554 
555         ArenaVector<ir::Expression *> newExprArgs(Allocator()->Adapter());
556         newExprArgs.push_back(newExprArg);
557 
558         auto *const exceptionReference = MakeTypeReference(Allocator(), "Exception");
559 
560         auto *const newExpr = Allocator()->New<ir::ETSNewClassInstanceExpression>(
561             exceptionReference, std::move(newExprArgs),
562             GlobalBuiltinExceptionType()->GetDeclNode()->AsClassDefinition());
563         newExpr->SetSignature(
564             ResolveConstructExpression(GlobalBuiltinExceptionType(), newExpr->GetArguments(), newExpr->Start()));
565         newExpr->SetTsType(GlobalBuiltinExceptionType());
566 
567         return Allocator()->New<ir::ThrowStatement>(newExpr);
568     }();
569 
570     ArenaVector<ir::Statement *> body(Allocator()->Adapter());
571     body.push_back(forLoop);
572     body.push_back(throwStmt);
573 
574     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
575     params.push_back(inputNameIdent);
576 
577     auto *const enumTypeAnnotation = MakeTypeReference(Allocator(), enumType->GetName());
578 
579     auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params),
580                                         std::move(body), enumTypeAnnotation, enumType->GetDecl()->IsDeclare());
581     function->AddFlag(ir::ScriptFunctionFlags::THROWS);
582 
583     auto *const functionIdent =
584         MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::VALUE_OF_METHOD_NAME);
585     function->SetIdent(functionIdent);
586     function->Scope()->BindInternalName(functionIdent->Name());
587 
588     MakeMethodDef(this, VarBinder()->AsETSBinder(), functionIdent, function);
589 
590     return {MakeGlobalSignature(this, function, enumType),
591             MakeProxyFunctionType(this, ETSEnumType::VALUE_OF_METHOD_NAME,
592                                   {function->Params()[0]->AsETSParameterExpression()->Variable()->AsLocalVariable()},
593                                   function, enumType)};
594 }
595 
CreateEnumValuesMethod(ir::Identifier * const itemsArrayIdent,ETSEnumInterface * const enumType)596 ETSEnumType::Method ETSChecker::CreateEnumValuesMethod(ir::Identifier *const itemsArrayIdent,
597                                                        ETSEnumInterface *const enumType)
598 {
599     auto *const paramScope =
600         VarBinder()->Allocator()->New<varbinder::FunctionParamScope>(Allocator(), Program()->GlobalScope());
601 
602     auto *const returnStmt = Allocator()->New<ir::ReturnStatement>(itemsArrayIdent);
603     ArenaVector<ir::Statement *> body(Allocator()->Adapter());
604     body.push_back(returnStmt);
605 
606     ArenaVector<ir::Expression *> params(Allocator()->Adapter());
607 
608     auto *const enumArrayTypeAnnotation =
609         Allocator()->New<ir::TSArrayType>(MakeTypeReference(Allocator(), enumType->GetName()));
610 
611     auto *const function = MakeFunction(this, VarBinder()->AsETSBinder(), paramScope, std::move(params),
612                                         std::move(body), enumArrayTypeAnnotation, enumType->GetDecl()->IsDeclare());
613 
614     auto *const functionIdent =
615         MakeQualifiedIdentifier(Allocator(), enumType->GetDecl(), ETSEnumType::VALUES_METHOD_NAME);
616     function->SetIdent(functionIdent);
617     function->Scope()->BindInternalName(functionIdent->Name());
618 
619     MakeMethodDef(this, VarBinder()->AsETSBinder(), functionIdent, function);
620 
621     return {MakeGlobalSignature(this, function, CreateETSArrayType(enumType)),
622             MakeProxyFunctionType(this, ETSEnumType::VALUES_METHOD_NAME, {}, function, CreateETSArrayType(enumType))};
623 }
624 }  // namespace panda::es2panda::checker
625