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 *> &¶ms,
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 *> ¶ms,
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