• 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 "ETSemitter.h"
17 
18 #include "compiler/core/ETSGen.h"
19 #include "varbinder/varbinder.h"
20 #include "varbinder/ETSBinder.h"
21 #include "ir/astNode.h"
22 #include "ir/expressions/identifier.h"
23 #include "ir/base/decorator.h"
24 #include "ir/base/methodDefinition.h"
25 #include "ir/base/classDefinition.h"
26 #include "ir/base/scriptFunction.h"
27 #include "ir/base/classProperty.h"
28 #include "ir/ts/tsEnumDeclaration.h"
29 #include "ir/ts/tsEnumMember.h"
30 #include "ir/ts/tsInterfaceDeclaration.h"
31 #include "ir/ts/tsInterfaceBody.h"
32 #include "ir/ts/tsTypeParameterDeclaration.h"
33 #include "ir/ts/tsTypeParameter.h"
34 #include "ir/typeNode.h"
35 #include "parser/program/program.h"
36 #include "checker/checker.h"
37 #include "checker/types/signature.h"
38 #include "checker/ETSchecker.h"
39 #include "checker/types/type.h"
40 #include "checker/types/ets/types.h"
41 #include "checker/types/ets/etsPartialTypeParameter.h"
42 #include "public/public.h"
43 
44 #include "assembly-program.h"
45 
46 namespace {
47 uint32_t g_litArrayValueCount = 0;
48 }  // namespace
49 
50 namespace ark::es2panda::compiler {
51 
52 #ifdef PANDA_WITH_ETS
53 static constexpr auto EXTENSION = panda_file::SourceLang::ETS;
54 #else
55 // NOTE: temporary dummy gn buildfix until ETS plugin has gn build support
56 static constexpr auto EXTENSION = panda_file::SourceLang::PANDA_ASSEMBLY;
57 #endif
58 
TranslateModifierFlags(ir::ModifierFlags modifierFlags)59 static uint32_t TranslateModifierFlags(ir::ModifierFlags modifierFlags)
60 {
61     uint32_t accessFlags = 0;
62 
63     if ((modifierFlags & ir::ModifierFlags::PRIVATE) != 0) {
64         accessFlags = ACC_PRIVATE;
65     } else if ((modifierFlags & ir::ModifierFlags::INTERNAL) != 0) {
66         if ((modifierFlags & ir::ModifierFlags::PROTECTED) != 0) {
67             accessFlags = ACC_PROTECTED;
68         }
69         // NOTE: torokg. Add ACC_INTERNAL access flag to libpandabase
70     } else if ((modifierFlags & ir::ModifierFlags::PROTECTED) != 0) {
71         accessFlags = ACC_PROTECTED;
72     } else {
73         accessFlags = ACC_PUBLIC;
74     }
75 
76     if ((modifierFlags & ir::ModifierFlags::STATIC) != 0) {
77         accessFlags |= ACC_STATIC;
78     }
79     if ((modifierFlags & ir::ModifierFlags::FINAL) != 0) {
80         accessFlags |= ACC_FINAL;
81     }
82     // NOTE: should be ModifierFlags::READONLY
83     if ((modifierFlags & ir::ModifierFlags::READONLY) != 0) {
84         accessFlags |= ACC_READONLY;
85     }
86     if ((modifierFlags & ir::ModifierFlags::ABSTRACT) != 0) {
87         accessFlags |= ACC_ABSTRACT;
88     }
89     if ((modifierFlags & ir::ModifierFlags::NATIVE) != 0) {
90         accessFlags |= ACC_NATIVE;
91     }
92 
93     return accessFlags;
94 }
95 
PandasmTypeWithRank(checker::Type const * type,uint32_t rank=0)96 static pandasm::Type PandasmTypeWithRank(checker::Type const *type, uint32_t rank = 0)
97 {
98     if (type->IsETSTypeParameter()) {
99         return PandasmTypeWithRank(type->AsETSTypeParameter()->GetConstraintType());
100     }
101     if (type->IsETSNonNullishType()) {
102         return PandasmTypeWithRank(type->AsETSNonNullishType()->GetUnderlying());
103     }
104     if (type->IsETSPartialTypeParameter()) {
105         return PandasmTypeWithRank(type->AsETSPartialTypeParameter()->GetUnderlying());
106     }
107     if (type->IsETSUnionType()) {
108         return PandasmTypeWithRank(type->AsETSUnionType()->GetAssemblerLUB());
109     }
110 
111     std::stringstream ss;
112     type->ToAssemblerType(ss);
113     return pandasm::Type(ss.str(), rank == 0 ? type->Rank() : rank);
114 }
115 
GenScriptFunction(const ir::ScriptFunction * scriptFunc,ETSEmitter * emitter)116 static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc, ETSEmitter *emitter)
117 {
118     auto *funcScope = scriptFunc->Scope();
119     auto *paramScope = funcScope->ParamScope();
120 
121     auto func = pandasm::Function(funcScope->InternalName().Mutf8(), EXTENSION);
122     func.params.reserve(paramScope->Params().size());
123 
124     for (const auto *var : paramScope->Params()) {
125         func.params.emplace_back(PandasmTypeWithRank(var->TsType()), EXTENSION);
126     }
127 
128     if (scriptFunc->IsConstructor() || scriptFunc->IsStaticBlock()) {
129         func.returnType = pandasm::Type(Signatures::PRIMITIVE_VOID, 0);
130     } else {
131         func.returnType = PandasmTypeWithRank(scriptFunc->Signature()->ReturnType());
132     }
133 
134     uint32_t accessFlags = 0;
135     if (!scriptFunc->IsStaticBlock()) {
136         const auto *methodDef = util::Helpers::GetContainingClassMethodDefinition(scriptFunc);
137         accessFlags |= TranslateModifierFlags(methodDef->Modifiers());
138     }
139     if (scriptFunc->HasRestParameter()) {
140         accessFlags |= ACC_VARARGS;
141     }
142     func.metadata->SetAccessFlags(accessFlags);
143 
144     if (!scriptFunc->Annotations().empty()) {
145         auto baseName = scriptFunc->Id()->Name().Mutf8();
146         func.metadata->SetAnnotations(emitter->GenCustomAnnotations(scriptFunc->Annotations(), baseName));
147     }
148     return func;
149 }
150 
GenFunctionSignature()151 pandasm::Function *ETSFunctionEmitter::GenFunctionSignature()
152 {
153     auto *scriptFunc = Cg()->RootNode()->AsScriptFunction();
154     auto *emitter = static_cast<ETSEmitter *>(Cg()->Context()->emitter);
155     auto func = GenScriptFunction(scriptFunc, emitter);
156 
157     if (Cg()->RootNode()->AsScriptFunction()->IsExternal()) {
158         func.metadata->SetAttribute(Signatures::EXTERNAL);
159     }
160 
161     auto *funcElement = new pandasm::Function(func.name, func.language);
162     *funcElement = std::move(func);
163     GetProgramElement()->SetFunction(funcElement);
164     funcElement->regsNum = VReg::REG_START - Cg()->TotalRegsNum();
165 
166     return funcElement;
167 }
168 
GenVariableSignature(pandasm::debuginfo::LocalVariable & variableDebug,varbinder::LocalVariable * variable) const169 void ETSFunctionEmitter::GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug,
170                                               [[maybe_unused]] varbinder::LocalVariable *variable) const
171 {
172     variableDebug.signature = Signatures::ANY;
173     variableDebug.signatureType = Signatures::ANY;
174 }
175 
GenFunctionAnnotations(pandasm::Function * func)176 void ETSFunctionEmitter::GenFunctionAnnotations([[maybe_unused]] pandasm::Function *func) {}
177 
GenExternalFunction(checker::Signature * signature,bool isCtor)178 static pandasm::Function GenExternalFunction(checker::Signature *signature, bool isCtor)
179 {
180     auto func = pandasm::Function(signature->InternalName().Mutf8(), EXTENSION);
181 
182     for (auto param : signature->Params()) {
183         func.params.emplace_back(PandasmTypeWithRank(param->TsType()), EXTENSION);
184     }
185     func.returnType = PandasmTypeWithRank(signature->ReturnType());
186 
187     if (isCtor) {
188         func.metadata->SetAttribute(Signatures::CONSTRUCTOR);
189     }
190     func.metadata->SetAttribute(Signatures::EXTERNAL);
191 
192     return func;
193 }
194 
GenerateMangledName(const std::string & baseName,const std::string & propName)195 static std::string GenerateMangledName(const std::string &baseName, const std::string &propName)
196 {
197     return baseName + "$" + propName;
198 }
199 
GenAnnotation()200 void ETSEmitter::GenAnnotation()
201 {
202     Program()->lang = EXTENSION;
203     const auto *varbinder = static_cast<varbinder::ETSBinder *>(Context()->parserProgram->VarBinder());
204 
205     auto *globalRecordTable = varbinder->GetGlobalRecordTable();
206     auto baseName = varbinder->GetRecordTable()->RecordName().Mutf8();
207     for (auto *annoDecl : globalRecordTable->AnnotationDeclarations()) {
208         auto newBaseName = GenerateMangledName(baseName, annoDecl->GetBaseName()->Name().Mutf8());
209         GenCustomAnnotationRecord(annoDecl, newBaseName, annoDecl->IsDeclare());
210     }
211 
212     for (auto *classDecl : globalRecordTable->ClassDefinitions()) {
213         GenClassRecord(classDecl, classDecl->IsDeclare());
214     }
215 
216     for (auto *interfaceDecl : globalRecordTable->InterfaceDeclarations()) {
217         GenInterfaceRecord(interfaceDecl, interfaceDecl->IsDeclare());
218     }
219 
220     for (auto *signature : globalRecordTable->Signatures()) {
221         auto *scriptFunc = signature->Node()->AsScriptFunction();
222         auto func = GenScriptFunction(scriptFunc, this);
223         if (scriptFunc->IsDeclare()) {
224             func.metadata->SetAttribute(Signatures::EXTERNAL);
225         }
226         if (scriptFunc->IsAsyncFunc()) {
227             std::vector<pandasm::AnnotationData> annotations;
228             annotations.push_back(GenAnnotationAsync(scriptFunc));
229             func.metadata->SetAnnotations(std::move(annotations));
230         }
231         Program()->functionTable.emplace(func.name, std::move(func));
232     }
233 
234     for (auto [extProg, recordTable] : varbinder->GetExternalRecordTable()) {
235         (void)extProg;
236         if (recordTable == varbinder->GetRecordTable()) {
237             continue;
238         }
239         GenExternalRecord(recordTable);
240     }
241 
242     const auto *checker = static_cast<checker::ETSChecker *>(Context()->checker);
243 
244     for (auto [arrType, signature] : checker->GlobalArrayTypes()) {
245         GenGlobalArrayRecord(arrType, signature);
246     }
247 }
248 
GenExternalRecord(varbinder::RecordTable * recordTable)249 void ETSEmitter::GenExternalRecord(varbinder::RecordTable *recordTable)
250 {
251     bool isGenStdLib = recordTable->Program()->VarBinder()->IsGenStdLib();
252     const auto *varbinder = static_cast<const varbinder::ETSBinder *>(Context()->parserProgram->VarBinder());
253     auto baseName = varbinder->GetRecordTable()->RecordName().Mutf8();
254     for (auto *annoDecl : recordTable->AnnotationDeclarations()) {
255         auto newBaseName = GenerateMangledName(baseName, annoDecl->GetBaseName()->Name().Mutf8());
256         GenCustomAnnotationRecord(annoDecl, newBaseName, !isGenStdLib);
257     }
258 
259     for (auto *classDecl : recordTable->ClassDefinitions()) {
260         GenClassRecord(classDecl, !isGenStdLib);
261     }
262 
263     for (auto *interfaceDecl : recordTable->InterfaceDeclarations()) {
264         GenInterfaceRecord(interfaceDecl, !isGenStdLib);
265     }
266 
267     for (auto *signature : recordTable->Signatures()) {
268         auto func = GenScriptFunction(signature->Node()->AsScriptFunction(), this);
269 
270         if (!isGenStdLib) {
271             func.metadata->SetAttribute(Signatures::EXTERNAL);
272         }
273 
274         Program()->functionTable.emplace(func.name, std::move(func));
275     }
276 }
277 
278 // Helper function to reduce EmitDefaultFieldValue size and pass code check
CreateScalarValue(const checker::Type * type,checker::TypeFlag typeKind)279 static pandasm::ScalarValue CreateScalarValue(const checker::Type *type, checker::TypeFlag typeKind)
280 {
281     switch (typeKind) {
282         case checker::TypeFlag::ETS_BOOLEAN: {
283             return pandasm::ScalarValue::Create<pandasm::Value::Type::U1>(
284                 static_cast<uint8_t>(type->AsETSBooleanType()->GetValue()));
285         }
286         case checker::TypeFlag::BYTE: {
287             return pandasm::ScalarValue::Create<pandasm::Value::Type::I8>(type->AsByteType()->GetValue());
288         }
289         case checker::TypeFlag::SHORT: {
290             return pandasm::ScalarValue::Create<pandasm::Value::Type::I16>(type->AsShortType()->GetValue());
291         }
292         case checker::TypeFlag::INT: {
293             return pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(type->AsIntType()->GetValue());
294         }
295         case checker::TypeFlag::LONG: {
296             return pandasm::ScalarValue::Create<pandasm::Value::Type::I64>(type->AsLongType()->GetValue());
297         }
298         case checker::TypeFlag::FLOAT: {
299             return pandasm::ScalarValue::Create<pandasm::Value::Type::F32>(type->AsFloatType()->GetValue());
300         }
301         case checker::TypeFlag::DOUBLE: {
302             return pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(type->AsDoubleType()->GetValue());
303         }
304         case checker::TypeFlag::CHAR: {
305             return pandasm::ScalarValue::Create<pandasm::Value::Type::U16>(type->AsCharType()->GetValue());
306         }
307         case checker::TypeFlag::ETS_OBJECT: {
308             return pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(
309                 type->AsETSObjectType()->AsETSStringType()->GetValue().Mutf8());
310         }
311         default: {
312             UNREACHABLE();
313         }
314     }
315 }
316 
EmitDefaultFieldValue(pandasm::Field & classField,const ir::Expression * init)317 void ETSEmitter::EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init)
318 {
319     if (init == nullptr) {
320         return;
321     }
322 
323     const auto *type = init->TsType();
324 
325     if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
326         return;
327     }
328 
329     auto typeKind = checker::ETSChecker::TypeKind(type);
330     classField.metadata->SetFieldType(classField.type);
331     classField.metadata->SetValue(CreateScalarValue(type, typeKind));
332 }
333 
GenInterfaceMethodDefinition(const ir::MethodDefinition * methodDef,bool external)334 void ETSEmitter::GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external)
335 {
336     auto *scriptFunc = methodDef->Function();
337     auto func = GenScriptFunction(scriptFunc, this);
338 
339     if (external) {
340         func.metadata->SetAttribute(Signatures::EXTERNAL);
341     }
342 
343     if (scriptFunc->Body() != nullptr) {
344         return;
345     }
346 
347     func.metadata->SetAccessFlags(func.metadata->GetAccessFlags() | ACC_ABSTRACT);
348     Program()->functionTable.emplace(func.name, std::move(func));
349 }
350 
GenClassField(const ir::ClassProperty * prop,pandasm::Record & classRecord,bool external)351 void ETSEmitter::GenClassField(const ir::ClassProperty *prop, pandasm::Record &classRecord, bool external)
352 {
353     auto field = pandasm::Field(Program()->lang);
354     field.name = prop->Id()->Name().Mutf8();
355     field.type = PandasmTypeWithRank(prop->TsType());
356     field.metadata->SetAccessFlags(TranslateModifierFlags(prop->Modifiers()));
357 
358     if (external || prop->IsDeclare()) {
359         field.metadata->SetAttribute(Signatures::EXTERNAL);
360     } else if (prop->TsType()->IsETSPrimitiveType() || prop->TsType()->IsETSStringType()) {
361         EmitDefaultFieldValue(field, prop->Value());
362     } else if (prop->TsType()->IsETSEnumType()) {
363         CreateEnumProp(prop, field);
364     }
365 
366     classRecord.fieldList.emplace_back(std::move(field));
367 }
368 
GenClassInheritedFields(const checker::ETSObjectType * baseType,pandasm::Record & classRecord)369 void ETSEmitter::GenClassInheritedFields(const checker::ETSObjectType *baseType, pandasm::Record &classRecord)
370 {
371     std::vector<const varbinder::LocalVariable *> foreignProps = baseType->ForeignProperties();
372 
373     for (const auto *foreignProp : foreignProps) {
374         auto *declNode = foreignProp->Declaration()->Node();
375         if (!declNode->IsClassProperty()) {
376             continue;
377         }
378 
379         GenClassField(declNode->AsClassProperty(), classRecord, true);
380     }
381 }
382 
GenGlobalArrayRecord(checker::ETSArrayType * arrayType,checker::Signature * signature)383 void ETSEmitter::GenGlobalArrayRecord(checker::ETSArrayType *arrayType, checker::Signature *signature)
384 {
385     std::stringstream ss;
386     arrayType->ToAssemblerTypeWithRank(ss);
387 
388     auto arrayRecord = pandasm::Record(ss.str(), Program()->lang);
389 
390     auto func = GenExternalFunction(signature, true);
391     func.params.emplace(func.params.begin(), pandasm::Type(ss.str(), 0), EXTENSION);
392 
393     Program()->functionTable.emplace(func.name, std::move(func));
394 
395     arrayRecord.metadata->SetAttribute(Signatures::EXTERNAL);
396     Program()->recordTable.emplace(arrayRecord.name, std::move(arrayRecord));
397     Program()->arrayTypes.emplace(PandasmTypeWithRank(arrayType));
398 }
399 
GenInterfaceRecord(const ir::TSInterfaceDeclaration * interfaceDecl,bool external)400 void ETSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external)
401 {
402     auto *baseType = interfaceDecl->TsType()->AsETSObjectType();
403 
404     auto interfaceRecord = pandasm::Record(interfaceDecl->InternalName().Mutf8(), Program()->lang);
405     if (external) {
406         interfaceRecord.metadata->SetAttribute(Signatures::EXTERNAL);
407     }
408 
409     uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE;
410 
411     if (interfaceDecl->IsStatic()) {
412         accessFlags |= ACC_STATIC;
413     }
414 
415     interfaceRecord.metadata->SetAccessFlags(accessFlags);
416     interfaceRecord.sourceFile =
417         Context()->parserProgram->VarBinder()->Program()->SourceFile().GetAbsolutePath().Mutf8();
418     interfaceRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT);
419 
420     for (auto *it : baseType->Interfaces()) {
421         auto *declNode = it->GetDeclNode();
422         ASSERT(declNode->IsTSInterfaceDeclaration());
423         std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8();
424         interfaceRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name);
425     }
426 
427     GenClassInheritedFields(baseType, interfaceRecord);
428 
429     for (const auto *prop : interfaceDecl->Body()->Body()) {
430         if (prop->IsClassProperty()) {
431             GenClassField(prop->AsClassProperty(), interfaceRecord, external);
432         } else if (prop->IsMethodDefinition()) {
433             GenInterfaceMethodDefinition(prop->AsMethodDefinition(), external);
434         }
435     }
436 
437     Program()->recordTable.emplace(interfaceRecord.name, std::move(interfaceRecord));
438 }
439 
GenAnnotations(const ir::ClassDefinition * classDef)440 std::vector<pandasm::AnnotationData> ETSEmitter::GenAnnotations(const ir::ClassDefinition *classDef)
441 {
442     std::vector<pandasm::AnnotationData> annotations;
443     const ir::AstNode *parent = classDef->Parent();
444     while (parent != nullptr) {
445         if (parent->IsMethodDefinition()) {
446             annotations.emplace_back(GenAnnotationEnclosingMethod(parent->AsMethodDefinition()));
447             annotations.emplace_back(GenAnnotationInnerClass(classDef, parent));
448             break;
449         }
450         if (parent->IsClassDefinition()) {
451             annotations.emplace_back(GenAnnotationEnclosingClass(
452                 parent->AsClassDefinition()->TsType()->AsETSObjectType()->AssemblerName().Utf8()));
453             annotations.emplace_back(GenAnnotationInnerClass(classDef, parent));
454             break;
455         }
456         parent = parent->Parent();
457     }
458 
459     auto classIdent = classDef->Ident()->Name().Mutf8();
460     bool isConstruct = classIdent == Signatures::JSNEW_CLASS;
461     if (isConstruct || classIdent == Signatures::JSCALL_CLASS) {
462         auto *callNames = Context()->checker->AsETSChecker()->DynamicCallNames(isConstruct);
463         annotations.push_back(GenAnnotationDynamicCall(*callNames));
464     }
465 
466     return annotations;
467 }
468 
GetAccessFlags(const ir::ClassDefinition * classDef)469 static uint32_t GetAccessFlags(const ir::ClassDefinition *classDef)
470 {
471     uint32_t accessFlags = ACC_PUBLIC;
472     if (classDef->IsAbstract()) {
473         accessFlags |= ACC_ABSTRACT;
474     } else if (classDef->IsFinal()) {
475         accessFlags |= ACC_FINAL;
476     }
477 
478     if (classDef->IsStatic()) {
479         accessFlags |= ACC_STATIC;
480     }
481 
482     return accessFlags;
483 }
484 
GenClassRecord(const ir::ClassDefinition * classDef,bool external)485 void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool external)
486 {
487     auto classRecord = pandasm::Record(classDef->InternalName().Mutf8(), Program()->lang);
488     auto baseName = classDef->Ident()->Name().Mutf8();
489     if (external) {
490         classRecord.metadata->SetAttribute(Signatures::EXTERNAL);
491     }
492 
493     if (!classDef->Annotations().empty()) {
494         classRecord.metadata->SetAnnotations(GenCustomAnnotations(classDef->Annotations(), baseName));
495     }
496 
497     uint32_t accessFlags = GetAccessFlags(classDef);
498     classRecord.metadata->SetAccessFlags(accessFlags);
499     classRecord.sourceFile = Context()->parserProgram->VarBinder()->Program()->SourceFile().GetAbsolutePath().Mutf8();
500 
501     auto *baseType = classDef->TsType()->AsETSObjectType();
502     if (baseType->SuperType() != nullptr) {
503         classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE,
504                                                 baseType->SuperType()->AssemblerName().Mutf8());
505     } else {
506         // NOTE: rtakacs. Replace the whole if block (below) with assert when lambda objects have super class.
507         if (baseType->AssemblerName().Mutf8() != Signatures::BUILTIN_OBJECT) {
508             classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT);
509         }
510     }
511 
512     for (auto *it : baseType->Interfaces()) {
513         // We do not need to add dynamic interfaces
514         if (it->IsETSDynamicType()) {
515             continue;
516         }
517 
518         auto *declNode = it->GetDeclNode();
519         // NOTE: itrubachev. replace it with ASSERT(decl_node->IsTSInterfaceDeclaration())
520         // after adding proper creation of lambda object in ETSFunctionType::AssignmentSource
521         if (!declNode->IsTSInterfaceDeclaration()) {
522             continue;
523         }
524         std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8();
525         classRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name);
526     }
527 
528     GenClassInheritedFields(baseType, classRecord);
529     for (const auto *prop : classDef->Body()) {
530         if (!prop->IsClassProperty()) {
531             continue;
532         }
533 
534         GenClassField(prop->AsClassProperty(), classRecord, external);
535     }
536 
537     std::vector<pandasm::AnnotationData> annotations = GenAnnotations(classDef);
538     if (!annotations.empty()) {
539         classRecord.metadata->SetAnnotations(std::move(annotations));
540     }
541 
542     Program()->recordTable.emplace(classRecord.name, std::move(classRecord));
543 }
544 
545 // Helper function to check if the unary expression is a numeric literal with negation.
546 // This expression should be handled during lowering with the associated issue number.
IsNegativeLiteralNode(const ir::UnaryExpression * expr)547 static bool IsNegativeLiteralNode(const ir::UnaryExpression *expr)
548 {
549     return expr->OperatorType() == lexer::TokenType::PUNCTUATOR_MINUS && expr->Argument()->IsNumberLiteral();
550 }
551 
CreateEnumProp(const ir::ClassProperty * prop,pandasm::Field & field)552 void ETSEmitter::CreateEnumProp(const ir::ClassProperty *prop, pandasm::Field &field)
553 {
554     if (prop->Value() == nullptr) {
555         return;
556     }
557     auto *init = prop->Value()->AsMemberExpression()->PropVar()->Declaration()->Node()->AsTSEnumMember()->Init();
558     field.metadata->SetFieldType(field.type);
559     if (init->IsNumberLiteral()) {
560         auto value = init->AsNumberLiteral()->Number().GetInt();
561         field.metadata->SetValue(pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(value));
562     } else if (init->IsStringLiteral()) {
563         auto value = init->AsStringLiteral()->Str().Mutf8();
564         field.metadata->SetValue(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(value));
565     } else if (init->IsUnaryExpression() && IsNegativeLiteralNode(init->AsUnaryExpression())) {
566         double doubleValue = (-1) * init->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number().GetDouble();
567         field.metadata->SetValue(pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(doubleValue));
568     } else {
569         UNREACHABLE();
570     }
571 }
572 
ProcessArrayExpression(std::string & baseName,std::vector<std::pair<std::string,std::vector<pandasm::LiteralArray::Literal>>> & result,std::vector<pandasm::LiteralArray::Literal> & literals,const ir::Expression * elem)573 void ETSEmitter::ProcessArrayExpression(
574     std::string &baseName, std::vector<std::pair<std::string, std::vector<pandasm::LiteralArray::Literal>>> &result,
575     std::vector<pandasm::LiteralArray::Literal> &literals, const ir::Expression *elem)
576 {
577     auto litArrays = CreateLiteralArray(baseName, elem);
578     auto emplaceLiteral = [&literals](panda_file::LiteralTag tag, const auto &value) {
579         literals.emplace_back(pandasm::LiteralArray::Literal {tag, value});
580     };
581 
582     emplaceLiteral(panda_file::LiteralTag::TAGVALUE, static_cast<uint8_t>(panda_file::LiteralTag::LITERALARRAY));
583     emplaceLiteral(panda_file::LiteralTag::LITERALARRAY, litArrays.back().first);
584     for (const auto &item : litArrays) {
585         result.push_back(item);
586     }
587 }
588 
ProcessEnumExpression(std::vector<pandasm::LiteralArray::Literal> & literals,const ir::Expression * elem)589 static void ProcessEnumExpression(std::vector<pandasm::LiteralArray::Literal> &literals, const ir::Expression *elem)
590 {
591     auto *memberExpr = elem->IsCallExpression() ? elem->AsCallExpression()->Arguments()[0]->AsMemberExpression()
592                                                 : elem->AsMemberExpression();
593     auto *init = memberExpr->PropVar()->Declaration()->Node()->AsTSEnumMember()->Init();
594     if (init->IsNumberLiteral()) {
595         auto enumValue = static_cast<uint32_t>(init->AsNumberLiteral()->Number().GetInt());
596         literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE,
597                                                               static_cast<uint8_t>(panda_file::LiteralTag::INTEGER)});
598         literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::INTEGER, enumValue});
599     } else {
600         auto enumValue = init->AsStringLiteral()->Str().Mutf8();
601         literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE,
602                                                               static_cast<uint8_t>(panda_file::LiteralTag::STRING)});
603         literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::STRING, enumValue});
604     }
605 }
606 
ProcessArrayElement(const ir::Expression * elem,std::vector<pandasm::LiteralArray::Literal> & literals,std::string & baseName,LiteralArrayVector & result)607 void ETSEmitter::ProcessArrayElement(const ir::Expression *elem, std::vector<pandasm::LiteralArray::Literal> &literals,
608                                      std::string &baseName, LiteralArrayVector &result)
609 {
610     switch (elem->Type()) {
611         case ir::AstNodeType::NUMBER_LITERAL: {
612             auto doubleValue = elem->AsNumberLiteral()->Number().GetDouble();
613             literals.emplace_back(pandasm::LiteralArray::Literal {
614                 panda_file::LiteralTag::TAGVALUE, static_cast<uint8_t>(panda_file::LiteralTag::DOUBLE)});
615             literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::DOUBLE, doubleValue});
616             break;
617         }
618         case ir::AstNodeType::BOOLEAN_LITERAL: {
619             bool boolValue = elem->AsBooleanLiteral()->Value();
620             literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE,
621                                                                   static_cast<uint8_t>(panda_file::LiteralTag::BOOL)});
622             literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::BOOL, boolValue});
623             break;
624         }
625         case ir::AstNodeType::STRING_LITERAL: {
626             std::string stringValue {elem->AsStringLiteral()->Str().Utf8()};
627             literals.emplace_back(pandasm::LiteralArray::Literal {
628                 panda_file::LiteralTag::TAGVALUE, static_cast<uint8_t>(panda_file::LiteralTag::STRING)});
629             literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::STRING, stringValue});
630             break;
631         }
632         case ir::AstNodeType::ARRAY_EXPRESSION: {
633             ProcessArrayExpression(baseName, result, literals, elem);
634             break;
635         }
636         case ir::AstNodeType::MEMBER_EXPRESSION:
637         case ir::AstNodeType::CALL_EXPRESSION: {
638             ProcessEnumExpression(literals, elem);
639             break;
640         }
641         case ir::AstNodeType::UNARY_EXPRESSION: {
642             double doubleValue = (-1) * elem->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number().GetDouble();
643             literals.emplace_back(pandasm::LiteralArray::Literal {
644                 panda_file::LiteralTag::TAGVALUE, static_cast<uint8_t>(panda_file::LiteralTag::DOUBLE)});
645             literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::DOUBLE, doubleValue});
646             break;
647         }
648         default:
649             UNREACHABLE();
650             break;
651     }
652 }
653 
CreateLiteralArray(std::string & baseName,const ir::Expression * array)654 LiteralArrayVector ETSEmitter::CreateLiteralArray(std::string &baseName, const ir::Expression *array)
655 {
656     LiteralArrayVector result;
657     std::vector<pandasm::LiteralArray::Literal> literals;
658     ArenaVector<ir::Expression *> elements {array->AsArrayExpression()->Elements()};
659 
660     for (const auto *elem : elements) {
661         ProcessArrayElement(elem, literals, baseName, result);
662     }
663 
664     std::string litArrayName = GenerateMangledName(baseName, std::to_string(g_litArrayValueCount));
665     ++g_litArrayValueCount;
666     result.emplace_back(litArrayName, literals);
667     return result;
668 }
669 
CreateLiteralArrayProp(const ir::ClassProperty * prop,std::string & baseName,pandasm::Field & field)670 void ETSEmitter::CreateLiteralArrayProp(const ir::ClassProperty *prop, std::string &baseName, pandasm::Field &field)
671 {
672     uint8_t rank = 1;
673     auto *elemType = prop->TsType()->AsETSArrayType()->ElementType();
674     while (elemType->IsETSArrayType()) {
675         ++rank;
676         elemType = elemType->AsETSArrayType()->ElementType();
677     }
678     if (elemType->IsETSEnumType()) {
679         field.type = PandasmTypeWithRank(elemType, rank);
680     } else {
681         std::stringstream ss;
682         elemType->ToAssemblerType(ss);
683         field.type = pandasm::Type(ss.str(), rank);
684     }
685 
686     auto value = prop->Value();
687     if (value != nullptr) {
688         std::string newBaseName = GenerateMangledName(baseName, field.name);
689         auto litArray = CreateLiteralArray(newBaseName, value);
690         for (const auto &item : litArray) {
691             Program()->literalarrayTable.emplace(item.first, item.second);
692         }
693         field.metadata->SetValue(
694             pandasm::ScalarValue::Create<pandasm::Value::Type::LITERALARRAY>(std::string_view {litArray.back().first}));
695     }
696 }
697 
GenCustomAnnotationProp(const ir::ClassProperty * prop,std::string & baseName,pandasm::Record & record,bool external)698 void ETSEmitter::GenCustomAnnotationProp(const ir::ClassProperty *prop, std::string &baseName, pandasm::Record &record,
699                                          bool external)
700 {
701     auto field = pandasm::Field(Program()->lang);
702     auto *type = prop->TsType();
703     field.name = prop->Id()->Name().Mutf8();
704     field.type = PandasmTypeWithRank(type);
705     field.metadata->SetAccessFlags(TranslateModifierFlags(prop->Modifiers()));
706 
707     if (external) {
708         field.metadata->SetAttribute(Signatures::EXTERNAL);
709     } else if (type->IsETSEnumType()) {
710         CreateEnumProp(prop, field);
711     } else if (type->IsETSPrimitiveType() || type->IsETSStringType()) {
712         EmitDefaultFieldValue(field, prop->Value());
713     } else if (type->IsETSArrayType()) {
714         CreateLiteralArrayProp(prop, baseName, field);
715     } else {
716         UNREACHABLE();
717     }
718     record.fieldList.emplace_back(std::move(field));
719 }
720 
GenCustomAnnotationRecord(const ir::AnnotationDeclaration * annoDecl,std::string & baseName,bool external)721 void ETSEmitter::GenCustomAnnotationRecord(const ir::AnnotationDeclaration *annoDecl, std::string &baseName,
722                                            bool external)
723 {
724     auto annoRecord = pandasm::Record(annoDecl->InternalName().Mutf8(), Program()->lang);
725     if (Program()->recordTable.find(annoRecord.name) != Program()->recordTable.end()) {
726         return;
727     }
728 
729     if (external) {
730         annoRecord.metadata->SetAttribute(Signatures::EXTERNAL);
731     }
732 
733     uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_ANNOTATION;
734     annoRecord.metadata->SetAccessFlags(accessFlags);
735     annoRecord.sourceFile = Context()->parserProgram->VarBinder()->Program()->SourceFile().GetAbsolutePath().Mutf8();
736     for (auto *it : annoDecl->Properties()) {
737         GenCustomAnnotationProp(it->AsClassProperty(), baseName, annoRecord, external);
738     }
739 
740     Program()->recordTable.emplace(annoRecord.name, std::move(annoRecord));
741 }
742 
CreateAnnotationScalarValue(checker::TypeFlag typeKind,const ir::Literal * init)743 static pandasm::ScalarValue CreateAnnotationScalarValue(checker::TypeFlag typeKind, const ir::Literal *init)
744 {
745     switch (typeKind) {
746         case checker::TypeFlag::ETS_BOOLEAN: {
747             return pandasm::ScalarValue::Create<pandasm::Value::Type::U1>(
748                 static_cast<uint8_t>(init->AsBooleanLiteral()->Value()));
749         }
750         case checker::TypeFlag::BYTE: {
751             return pandasm::ScalarValue::Create<pandasm::Value::Type::I8>(init->AsNumberLiteral()->Number().GetInt());
752         }
753         case checker::TypeFlag::SHORT: {
754             return pandasm::ScalarValue::Create<pandasm::Value::Type::I16>(init->AsNumberLiteral()->Number().GetInt());
755         }
756         case checker::TypeFlag::INT: {
757             return pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(init->AsNumberLiteral()->Number().GetInt());
758         }
759         case checker::TypeFlag::LONG: {
760             return pandasm::ScalarValue::Create<pandasm::Value::Type::I64>(init->AsNumberLiteral()->Number().GetLong());
761         }
762         case checker::TypeFlag::FLOAT: {
763             return pandasm::ScalarValue::Create<pandasm::Value::Type::F32>(
764                 init->AsNumberLiteral()->Number().GetFloat());
765         }
766         case checker::TypeFlag::DOUBLE: {
767             return pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(
768                 init->AsNumberLiteral()->Number().GetDouble());
769         }
770         case checker::TypeFlag::ETS_OBJECT: {
771             return pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(init->AsStringLiteral()->Str().Mutf8());
772         }
773         default: {
774             UNREACHABLE();
775         }
776     }
777 }
778 
ProcessArrayType(const ir::ClassProperty * prop,std::string & baseName,const ir::Expression * init)779 pandasm::AnnotationElement ETSEmitter::ProcessArrayType(const ir::ClassProperty *prop, std::string &baseName,
780                                                         const ir::Expression *init)
781 {
782     auto propName = prop->Id()->Name().Mutf8();
783     std::string newBaseName = GenerateMangledName(baseName, propName);
784     auto litArrays = CreateLiteralArray(newBaseName, init);
785 
786     for (const auto &item : litArrays) {
787         Program()->literalarrayTable.emplace(item.first, item.second);
788     }
789 
790     return pandasm::AnnotationElement {
791         propName, std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(
792                       std::string_view {litArrays.back().first}))};
793 }
794 
GenCustomAnnotationElement(const ir::ClassProperty * prop,std::string & baseName)795 pandasm::AnnotationElement ETSEmitter::GenCustomAnnotationElement(const ir::ClassProperty *prop, std::string &baseName)
796 {
797     const auto *init = prop->Value();
798     const auto *type = init->TsType();
799     auto typeKind = checker::ETSChecker::TypeKind(type);
800     auto propName = prop->Id()->Name().Mutf8();
801     if (type->IsETSArrayType()) {
802         return ProcessArrayType(prop, baseName, init);
803     }
804     switch (checker::ETSChecker::TypeKind(
805         Context()->checker->AsETSChecker()->MaybeUnboxType(const_cast<checker::Type *>(type)))) {
806         case checker::TypeFlag::BYTE:
807         case checker::TypeFlag::SHORT:
808         case checker::TypeFlag::INT:
809         case checker::TypeFlag::LONG:
810         case checker::TypeFlag::FLOAT:
811         case checker::TypeFlag::DOUBLE:
812         case checker::TypeFlag::ETS_BOOLEAN:
813         case checker::TypeFlag::ETS_OBJECT: {
814             if (init->IsUnaryExpression() && IsNegativeLiteralNode(init->AsUnaryExpression())) {
815                 double negNumberValue =
816                     (-1) * init->AsUnaryExpression()->Argument()->AsNumberLiteral()->Number().GetDouble();
817                 return pandasm::AnnotationElement {
818                     propName, std::make_unique<pandasm::ScalarValue>(
819                                   pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(negNumberValue))};
820             }
821             return pandasm::AnnotationElement {propName, std::make_unique<pandasm::ScalarValue>(
822                                                              CreateAnnotationScalarValue(typeKind, init->AsLiteral()))};
823         }
824         case checker::TypeFlag::ETS_INT_ENUM: {
825             auto *initValue = init->AsMemberExpression()->PropVar()->Declaration()->Node()->AsTSEnumMember()->Init();
826             auto enumValue = static_cast<uint32_t>(initValue->AsNumberLiteral()->Number().GetInt());
827             auto intEnumValue = pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(enumValue);
828             return pandasm::AnnotationElement {propName, std::make_unique<pandasm::ScalarValue>(intEnumValue)};
829         }
830         case checker::TypeFlag::ETS_STRING_ENUM: {
831             auto *initValue = init->AsMemberExpression()->PropVar()->Declaration()->Node()->AsTSEnumMember()->Init();
832             auto enumValue = initValue->AsStringLiteral()->Str().Mutf8();
833             auto stringValue = pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(enumValue);
834             return pandasm::AnnotationElement {propName, std::make_unique<pandasm::ScalarValue>(stringValue)};
835         }
836         default:
837             UNREACHABLE();
838     }
839 }
840 
GenCustomAnnotation(ir::AnnotationUsage * anno,std::string & baseName)841 pandasm::AnnotationData ETSEmitter::GenCustomAnnotation(ir::AnnotationUsage *anno, std::string &baseName)
842 {
843     auto *annoDecl = anno->GetBaseName()->Variable()->Declaration()->Node()->AsAnnotationDeclaration();
844     pandasm::AnnotationData annotation(annoDecl->InternalName().Mutf8());
845     if (annoDecl->IsImportDeclaration()) {
846         auto annoRecord = pandasm::Record(annoDecl->InternalName().Mutf8(), Program()->lang);
847         annoRecord.metadata->SetAttribute(Signatures::EXTERNAL);
848         uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_ANNOTATION;
849         annoRecord.metadata->SetAccessFlags(accessFlags);
850         Program()->recordTable.emplace(annoRecord.name, std::move(annoRecord));
851     }
852 
853     for (auto *prop : anno->Properties()) {
854         annotation.AddElement(GenCustomAnnotationElement(prop->AsClassProperty(), baseName));
855     }
856     return annotation;
857 }
858 
GenCustomAnnotations(const ArenaVector<ir::AnnotationUsage * > & annotationUsages,std::string & baseName)859 std::vector<pandasm::AnnotationData> ETSEmitter::GenCustomAnnotations(
860     const ArenaVector<ir::AnnotationUsage *> &annotationUsages, std::string &baseName)
861 {
862     std::vector<pandasm::AnnotationData> annotations;
863     for (auto *anno : annotationUsages) {
864         auto newBaseName = GenerateMangledName(baseName, anno->GetBaseName()->Name().Mutf8());
865         annotations.emplace_back(GenCustomAnnotation(anno, newBaseName));
866     }
867     return annotations;
868 }
869 
GenAnnotationSignature(const ir::ClassDefinition * classDef)870 pandasm::AnnotationData ETSEmitter::GenAnnotationSignature(const ir::ClassDefinition *classDef)
871 {
872     static constexpr std::string_view OBJECT = "Lstd/core/Object";
873     std::vector<pandasm::ScalarValue> parts {};
874     std::stringstream ss {};
875     const auto &params = classDef->TypeParams()->Params();
876 
877     bool firstIteration = true;
878     for (const auto *param : params) {
879         if (firstIteration) {
880             ss << Signatures::GENERIC_BEGIN;
881             firstIteration = false;
882         }
883         ss << param->Name()->Name() << Signatures::MANGLE_BEGIN;
884         parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
885 
886         std::stringstream {}.swap(ss);
887         if (param->Constraint() == nullptr) {
888             ss << OBJECT;
889         } else {
890             param->Constraint()->TsType()->ToAssemblerTypeWithRank(ss);
891             auto str = ss.str();
892             std::replace(str.begin(), str.end(), *Signatures::METHOD_SEPARATOR.begin(),
893                          *Signatures::NAMESPACE_SEPARATOR.begin());
894             std::stringstream {}.swap(ss);
895             ss << Signatures::CLASS_REF_BEGIN << str << Signatures::MANGLE_SEPARATOR;
896         }
897 
898         parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
899         std::stringstream {}.swap(ss);  // cleanup
900     }
901 
902     ss << Signatures::GENERIC_END;
903     parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
904 
905     std::stringstream {}.swap(ss);
906     if (classDef->TsType()->AsETSObjectType()->SuperType() == nullptr) {
907         ss << OBJECT;
908     } else {
909         ss << Signatures::CLASS_REF_BEGIN;
910         auto superType = classDef->TsType()->AsETSObjectType()->SuperType()->AssemblerName().Mutf8();
911         std::replace(superType.begin(), superType.end(), *Signatures::METHOD_SEPARATOR.begin(),
912                      *Signatures::NAMESPACE_SEPARATOR.begin());
913         ss << superType << Signatures::MANGLE_SEPARATOR;
914     }
915     parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
916 
917     GenAnnotationRecord(Signatures::ETS_ANNOTATION_SIGNATURE);
918     pandasm::AnnotationData signature(Signatures::ETS_ANNOTATION_SIGNATURE);
919     pandasm::AnnotationElement value(
920         Signatures::ANNOTATION_KEY_VALUE,
921         std::make_unique<pandasm::ArrayValue>(pandasm::Value::Type::STRING, std::move(parts)));
922     signature.AddElement(std::move(value));
923     return signature;
924 }
925 
GenAnnotationEnclosingMethod(const ir::MethodDefinition * methodDef)926 pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef)
927 {
928     GenAnnotationRecord(Signatures::ETS_ANNOTATION_ENCLOSING_METHOD);
929     pandasm::AnnotationData enclosingMethod(Signatures::ETS_ANNOTATION_ENCLOSING_METHOD);
930     pandasm::AnnotationElement value(
931         Signatures::ANNOTATION_KEY_VALUE,
932         std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::METHOD>(
933             methodDef->Function()->Scope()->InternalName().Mutf8())));
934     enclosingMethod.AddElement(std::move(value));
935     return enclosingMethod;
936 }
937 
GenAnnotationEnclosingClass(std::string_view className)938 pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingClass(std::string_view className)
939 {
940     GenAnnotationRecord(Signatures::ETS_ANNOTATION_ENCLOSING_CLASS);
941     pandasm::AnnotationData enclosingClass(Signatures::ETS_ANNOTATION_ENCLOSING_CLASS);
942     pandasm::AnnotationElement value(
943         Signatures::ANNOTATION_KEY_VALUE,
944         std::make_unique<pandasm::ScalarValue>(
945             pandasm::ScalarValue::Create<pandasm::Value::Type::RECORD>(pandasm::Type::FromName(className, true))));
946     enclosingClass.AddElement(std::move(value));
947     return enclosingClass;
948 }
949 
GenAnnotationInnerClass(const ir::ClassDefinition * classDef,const ir::AstNode * parent)950 pandasm::AnnotationData ETSEmitter::GenAnnotationInnerClass(const ir::ClassDefinition *classDef,
951                                                             const ir::AstNode *parent)
952 {
953     GenAnnotationRecord(Signatures::ETS_ANNOTATION_INNER_CLASS);
954     pandasm::AnnotationData innerClass(Signatures::ETS_ANNOTATION_INNER_CLASS);
955     const bool isAnonymous = (classDef->Modifiers() & ir::ClassDefinitionModifiers::ANONYMOUS) != 0;
956     pandasm::AnnotationElement name(Signatures::ANNOTATION_KEY_NAME,
957                                     std::make_unique<pandasm::ScalarValue>(
958                                         isAnonymous
959                                             ? pandasm::ScalarValue::Create<pandasm::Value::Type::STRING_NULLPTR>(0)
960                                             : pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(
961                                                   classDef->TsType()->AsETSObjectType()->AssemblerName().Mutf8())));
962     innerClass.AddElement(std::move(name));
963 
964     pandasm::AnnotationElement accessFlags(
965         Signatures::ANNOTATION_KEY_ACCESS_FLAGS,
966         std::make_unique<pandasm::ScalarValue>(
967             pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(TranslateModifierFlags(parent->Modifiers()))));
968     innerClass.AddElement(std::move(accessFlags));
969     return innerClass;
970 }
971 
FindAsyncImpl(ir::ScriptFunction * asyncFunc)972 ir::MethodDefinition *ETSEmitter::FindAsyncImpl(ir::ScriptFunction *asyncFunc)
973 {
974     std::string implName = checker::ETSChecker::GetAsyncImplName(asyncFunc->Id()->Name());
975     ir::AstNode *ownerNode = asyncFunc->Signature()->Owner()->GetDeclNode();
976     ASSERT(ownerNode != nullptr && ownerNode->IsClassDefinition());
977     const ir::ClassDefinition *classDef = ownerNode->AsClassDefinition();
978     ASSERT(classDef != nullptr);
979 
980     auto it = std::find_if(classDef->Body().rbegin(), classDef->Body().rend(), [&implName](ir::AstNode *node) {
981         return node->IsMethodDefinition() && node->AsMethodDefinition()->Id()->Name().Utf8() == implName;
982     });
983     if (it == classDef->Body().rend()) {
984         return nullptr;
985     }
986 
987     ir::MethodDefinition *method = (*it)->AsMethodDefinition();
988     auto *checker = static_cast<checker::ETSChecker *>(Context()->checker);
989     checker::TypeRelation *typeRel = checker->Relation();
990     checker::SavedTypeRelationFlagsContext savedFlagsCtx(typeRel, checker::TypeRelationFlag::NO_RETURN_TYPE_CHECK);
991     method->Function()->Signature()->Compatible(typeRel, asyncFunc->Signature());
992     auto overloadIt = method->Overloads().begin();
993     while (overloadIt != method->Overloads().end() && !typeRel->IsTrue()) {
994         method = *overloadIt;
995         method->Function()->Signature()->Compatible(typeRel, asyncFunc->Signature());
996         ++overloadIt;
997     }
998     return typeRel->IsTrue() ? method : nullptr;
999 }
1000 
GenAnnotationAsync(ir::ScriptFunction * scriptFunc)1001 pandasm::AnnotationData ETSEmitter::GenAnnotationAsync(ir::ScriptFunction *scriptFunc)
1002 {
1003     GenAnnotationRecord(Signatures::ETS_COROUTINE_ASYNC);
1004     const ir::MethodDefinition *impl = FindAsyncImpl(scriptFunc);
1005     ASSERT(impl != nullptr);
1006     pandasm::AnnotationData ann(Signatures::ETS_COROUTINE_ASYNC);
1007     pandasm::AnnotationElement value(
1008         Signatures::ANNOTATION_KEY_VALUE,
1009         std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::METHOD>(
1010             impl->Function()->Scope()->InternalName().Mutf8())));
1011     ann.AddElement(std::move(value));
1012     return ann;
1013 }
1014 
GenAnnotationDynamicCall(DynamicCallNamesMap & callNames)1015 pandasm::AnnotationData ETSEmitter::GenAnnotationDynamicCall(DynamicCallNamesMap &callNames)
1016 {
1017     GenAnnotationRecord(Signatures::ETS_ANNOTATION_DYNAMIC_CALL);
1018     pandasm::AnnotationData dynamicCallSig(Signatures::ETS_ANNOTATION_DYNAMIC_CALL);
1019     std::vector<pandasm::ScalarValue> allParts {};
1020     for (auto &[parts, startIdx] : callNames) {
1021         startIdx = allParts.size();
1022         for (const auto &str : parts) {
1023             allParts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(str.Utf8()));
1024         }
1025     }
1026     pandasm::AnnotationElement value(
1027         Signatures::ANNOTATION_KEY_VALUE,
1028         std::make_unique<pandasm::ArrayValue>(pandasm::Value::Type::STRING, std::move(allParts)));
1029     dynamicCallSig.AddElement(std::move(value));
1030     return dynamicCallSig;
1031 }
1032 
GenAnnotationRecord(std::string_view recordNameView,bool isRuntime,bool isType)1033 void ETSEmitter::GenAnnotationRecord(std::string_view recordNameView, bool isRuntime, bool isType)
1034 {
1035     const std::string recordName(recordNameView);
1036     const auto recordIt = Program()->recordTable.find(recordName);
1037     if (recordIt == Program()->recordTable.end()) {
1038         pandasm::Record record(recordName, EXTENSION);
1039         record.metadata->SetAttribute(Signatures::EXTERNAL);
1040         record.metadata->SetAttribute(Signatures::ANNOTATION_ATTRIBUTE);
1041         if (isRuntime && isType) {
1042             record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE,
1043                                                Signatures::RUNTIME_TYPE_ANNOTATION);
1044         } else if (isRuntime && !isType) {
1045             record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::RUNTIME_ANNOTATION);
1046         } else if (!isRuntime && isType) {
1047             record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::TYPE_ANNOTATION);
1048         }
1049         Program()->recordTable.emplace(record.name, std::move(record));
1050     }
1051 }
1052 }  // namespace ark::es2panda::compiler
1053