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/variableFlags.h"
21#include "varbinder/ETSBinder.h"
22#include "ir/astNode.h"
23#include "ir/expressions/identifier.h"
24#include "ir/base/decorator.h"
25#include "ir/base/methodDefinition.h"
26#include "ir/base/classDefinition.h"
27#include "ir/base/scriptFunction.h"
28#include "ir/base/classProperty.h"
29#include "ir/ts/tsEnumDeclaration.h"
30#include "ir/ts/tsEnumMember.h"
31#include "ir/ts/tsInterfaceDeclaration.h"
32#include "ir/ts/tsInterfaceBody.h"
33#include "ir/ts/tsTypeParameterDeclaration.h"
34#include "ir/ts/tsTypeParameter.h"
35#include "ir/typeNode.h"
36#include "parser/program/program.h"
37#include "checker/checker.h"
38#include "checker/types/signature.h"
39#include "checker/ETSchecker.h"
40#include "checker/types/type.h"
41#include "checker/types/ets/types.h"
42#include "public/public.h"
43
44#include "assembly-program.h"
45
46namespace ark::es2panda::compiler {
47
48#ifdef PANDA_WITH_ETS
49static constexpr auto EXTENSION = panda_file::SourceLang::ETS;
50#else
51// NOTE: temporary dummy gn buildfix until ETS plugin has gn build support
52static constexpr auto EXTENSION = panda_file::SourceLang::PANDA_ASSEMBLY;
53#endif
54
55static uint32_t TranslateModifierFlags(ir::ModifierFlags modifierFlags)
56{
57    uint32_t accessFlags = 0;
58
59    if ((modifierFlags & ir::ModifierFlags::PRIVATE) != 0) {
60        accessFlags = ACC_PRIVATE;
61    } else if ((modifierFlags & ir::ModifierFlags::INTERNAL) != 0) {
62        if ((modifierFlags & ir::ModifierFlags::PROTECTED) != 0) {
63            accessFlags = ACC_PROTECTED;
64        }
65        // NOTE: torokg. Add ACC_INTERNAL access flag to libpandabase
66    } else if ((modifierFlags & ir::ModifierFlags::PROTECTED) != 0) {
67        accessFlags = ACC_PROTECTED;
68    } else {
69        accessFlags = ACC_PUBLIC;
70    }
71
72    if ((modifierFlags & ir::ModifierFlags::STATIC) != 0) {
73        accessFlags |= ACC_STATIC;
74    }
75    if ((modifierFlags & ir::ModifierFlags::FINAL) != 0) {
76        accessFlags |= ACC_FINAL;
77    }
78    // NOTE: should be ModifierFlags::READONLY
79    if ((modifierFlags & ir::ModifierFlags::READONLY) != 0) {
80        accessFlags |= ACC_READONLY;
81    }
82    if ((modifierFlags & ir::ModifierFlags::ABSTRACT) != 0) {
83        accessFlags |= ACC_ABSTRACT;
84    }
85    if ((modifierFlags & ir::ModifierFlags::NATIVE) != 0) {
86        accessFlags |= ACC_NATIVE;
87    }
88
89    return accessFlags;
90}
91
92static pandasm::Type PandasmTypeWithRank(checker::Type const *type)
93{
94    if (type->IsETSTypeParameter()) {
95        return PandasmTypeWithRank(type->AsETSTypeParameter()->GetConstraintType());
96    }
97    if (type->IsETSNonNullishType()) {
98        return PandasmTypeWithRank(type->AsETSNonNullishType()->GetUnderlying());
99    }
100    if (type->IsETSUnionType()) {
101        return PandasmTypeWithRank(type->AsETSUnionType()->GetAssemblerLUB());
102    }
103
104    std::stringstream ss;
105    type->ToAssemblerType(ss);
106    return pandasm::Type(ss.str(), type->Rank());
107}
108
109static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc)
110{
111    auto *funcScope = scriptFunc->Scope();
112    auto *paramScope = funcScope->ParamScope();
113
114    auto func = pandasm::Function(funcScope->InternalName().Mutf8(), EXTENSION);
115    func.params.reserve(paramScope->Params().size());
116
117    for (const auto *var : paramScope->Params()) {
118        func.params.emplace_back(PandasmTypeWithRank(var->TsType()), EXTENSION);
119    }
120
121    if (scriptFunc->IsConstructor() || scriptFunc->IsStaticBlock()) {
122        func.returnType = pandasm::Type(Signatures::PRIMITIVE_VOID, 0);
123    } else {
124        func.returnType = PandasmTypeWithRank(scriptFunc->Signature()->ReturnType());
125    }
126
127    uint32_t accessFlags = 0;
128    if (!scriptFunc->IsStaticBlock()) {
129        const auto *methodDef = util::Helpers::GetContainingClassMethodDefinition(scriptFunc);
130        accessFlags |= TranslateModifierFlags(methodDef->Modifiers());
131    }
132    if (scriptFunc->HasRestParameter()) {
133        accessFlags |= ACC_VARARGS;
134    }
135    func.metadata->SetAccessFlags(accessFlags);
136
137    return func;
138}
139
140pandasm::Function *ETSFunctionEmitter::GenFunctionSignature()
141{
142    auto func = GenScriptFunction(Cg()->RootNode()->AsScriptFunction());
143
144    if (Cg()->RootNode()->AsScriptFunction()->IsExternal()) {
145        func.metadata->SetAttribute(Signatures::EXTERNAL);
146    }
147
148    auto *funcElement = new pandasm::Function(func.name, func.language);
149    *funcElement = std::move(func);
150    GetProgramElement()->SetFunction(funcElement);
151    funcElement->regsNum = VReg::REG_START - Cg()->TotalRegsNum();
152
153    return funcElement;
154}
155
156void ETSFunctionEmitter::GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug,
157                                              [[maybe_unused]] varbinder::LocalVariable *variable) const
158{
159    variableDebug.signature = Signatures::ANY;
160    variableDebug.signatureType = Signatures::ANY;
161}
162
163void ETSFunctionEmitter::GenFunctionAnnotations([[maybe_unused]] pandasm::Function *func) {}
164
165template <typename T>
166static pandasm::Function GenExternalFunction(T signature, bool isCtor)
167{
168    auto iter = signature.begin();
169    std::string name(*iter++);
170
171    auto func = pandasm::Function(name, EXTENSION);
172
173    while (iter != signature.end()) {
174        auto paramName = *iter++;
175        func.params.emplace_back(pandasm::Type(paramName, 0), EXTENSION);
176    }
177
178    func.returnType = pandasm::Type(Signatures::PRIMITIVE_VOID, 0);
179    if (isCtor) {
180        func.metadata->SetAttribute(Signatures::CONSTRUCTOR);
181    }
182    func.metadata->SetAttribute(Signatures::EXTERNAL);
183
184    return func;
185}
186
187static pandasm::Function GenExternalFunction(checker::Signature *signature, bool isCtor)
188{
189    auto func = pandasm::Function(signature->InternalName().Mutf8(), EXTENSION);
190
191    for (auto param : signature->Params()) {
192        func.params.emplace_back(PandasmTypeWithRank(param->TsType()), EXTENSION);
193    }
194    func.returnType = PandasmTypeWithRank(signature->ReturnType());
195
196    if (isCtor) {
197        func.metadata->SetAttribute(Signatures::CONSTRUCTOR);
198    }
199    func.metadata->SetAttribute(Signatures::EXTERNAL);
200
201    return func;
202}
203
204void ETSEmitter::GenAnnotation()
205{
206    Program()->lang = EXTENSION;
207    const auto *varbinder = static_cast<varbinder::ETSBinder *>(Context()->parserProgram->VarBinder());
208
209    auto *globalRecordTable = varbinder->GetGlobalRecordTable();
210
211    for (auto *classDecl : globalRecordTable->ClassDefinitions()) {
212        GenClassRecord(classDecl, false);
213    }
214
215    for (auto *interfaceDecl : globalRecordTable->InterfaceDeclarations()) {
216        GenInterfaceRecord(interfaceDecl, false);
217    }
218
219    for (auto *signature : globalRecordTable->Signatures()) {
220        auto *scriptFunc = signature->Node()->AsScriptFunction();
221        auto func = scriptFunc->Declare() ? GenExternalFunction(scriptFunc->Signature(), scriptFunc->IsConstructor())
222                                          : GenScriptFunction(scriptFunc);
223        if (scriptFunc->IsAsyncFunc()) {
224            std::vector<pandasm::AnnotationData> annotations;
225            annotations.push_back(GenAnnotationAsync(scriptFunc));
226            func.metadata->SetAnnotations(std::move(annotations));
227        }
228        Program()->functionTable.emplace(func.name, std::move(func));
229    }
230
231    for (auto [extProg, recordTable] : varbinder->GetExternalRecordTable()) {
232        (void)extProg;
233        GenExternalRecord(recordTable);
234    }
235
236    const auto *checker = static_cast<checker::ETSChecker *>(Context()->checker);
237
238    for (auto [arrType, signature] : checker->GlobalArrayTypes()) {
239        GenGlobalArrayRecord(arrType, signature);
240    }
241}
242
243void ETSEmitter::GenExternalRecord(varbinder::RecordTable *recordTable)
244{
245    bool isGenStdLib = recordTable->Program()->VarBinder()->IsGenStdLib();
246    for (auto *classDecl : recordTable->ClassDefinitions()) {
247        GenClassRecord(classDecl, !isGenStdLib);
248    }
249
250    for (auto *interfaceDecl : recordTable->InterfaceDeclarations()) {
251        GenInterfaceRecord(interfaceDecl, !isGenStdLib);
252    }
253
254    for (auto *signature : recordTable->Signatures()) {
255        auto func = GenScriptFunction(signature->Node()->AsScriptFunction());
256
257        if (!isGenStdLib) {
258            func.metadata->SetAttribute(Signatures::EXTERNAL);
259        }
260
261        Program()->functionTable.emplace(func.name, std::move(func));
262    }
263}
264
265// Helper function to reduce EmitDefaultFieldValue size and pass code check
266static pandasm::ScalarValue CreateScalarValue(const checker::Type *type, checker::TypeFlag typeKind)
267{
268    switch (typeKind) {
269        case checker::TypeFlag::ETS_BOOLEAN: {
270            return pandasm::ScalarValue::Create<pandasm::Value::Type::U1>(
271                static_cast<uint8_t>(type->AsETSBooleanType()->GetValue()));
272        }
273        case checker::TypeFlag::BYTE: {
274            return pandasm::ScalarValue::Create<pandasm::Value::Type::I8>(type->AsByteType()->GetValue());
275        }
276        case checker::TypeFlag::SHORT: {
277            return pandasm::ScalarValue::Create<pandasm::Value::Type::I16>(type->AsShortType()->GetValue());
278        }
279        case checker::TypeFlag::INT: {
280            return pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(type->AsIntType()->GetValue());
281        }
282        case checker::TypeFlag::LONG: {
283            return pandasm::ScalarValue::Create<pandasm::Value::Type::I64>(type->AsLongType()->GetValue());
284        }
285        case checker::TypeFlag::FLOAT: {
286            return pandasm::ScalarValue::Create<pandasm::Value::Type::F32>(type->AsFloatType()->GetValue());
287        }
288        case checker::TypeFlag::DOUBLE: {
289            return pandasm::ScalarValue::Create<pandasm::Value::Type::F64>(type->AsDoubleType()->GetValue());
290        }
291        case checker::TypeFlag::CHAR: {
292            return pandasm::ScalarValue::Create<pandasm::Value::Type::U16>(type->AsCharType()->GetValue());
293        }
294        case checker::TypeFlag::ETS_OBJECT: {
295            return pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(
296                type->AsETSObjectType()->AsETSStringType()->GetValue().Mutf8());
297        }
298        default: {
299            UNREACHABLE();
300        }
301    }
302}
303
304void ETSEmitter::EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init)
305{
306    if (init == nullptr) {
307        return;
308    }
309
310    const auto *type = init->TsType();
311
312    if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
313        return;
314    }
315
316    auto typeKind = checker::ETSChecker::TypeKind(type);
317    classField.metadata->SetFieldType(classField.type);
318    classField.metadata->SetValue(CreateScalarValue(type, typeKind));
319}
320
321void ETSEmitter::GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external)
322{
323    auto *scriptFunc = methodDef->Function();
324    auto func = GenScriptFunction(scriptFunc);
325
326    if (external) {
327        func.metadata->SetAttribute(Signatures::EXTERNAL);
328    }
329
330    if (scriptFunc->Body() != nullptr) {
331        return;
332    }
333
334    func.metadata->SetAccessFlags(func.metadata->GetAccessFlags() | ACC_ABSTRACT);
335    Program()->functionTable.emplace(func.name, std::move(func));
336}
337
338void ETSEmitter::GenClassField(const ir::ClassProperty *field, pandasm::Record &classRecord, bool external)
339{
340    GenField({field->TsType(), field->Id()->Name(), field->Value(), TranslateModifierFlags(field->Modifiers()),
341              classRecord, external || field->IsDeclare()});
342}
343
344void ETSEmitter::GenField(const GenFieldArguments &data)
345{
346    auto field = pandasm::Field(Program()->lang);
347    field.name = data.name.Mutf8();
348    field.type = PandasmTypeWithRank(data.tsType);
349    field.metadata->SetAccessFlags(data.accesFlags);
350
351    if (data.external) {
352        field.metadata->SetAttribute(Signatures::EXTERNAL);
353    } else if (data.tsType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) || data.tsType->IsETSStringType()) {
354        EmitDefaultFieldValue(field, data.value);
355    }
356
357    data.record.fieldList.emplace_back(std::move(field));
358}
359
360void ETSEmitter::GenClassInheritedFields(const checker::ETSObjectType *baseType, pandasm::Record &classRecord)
361{
362    std::vector<const varbinder::LocalVariable *> foreignProps = baseType->ForeignProperties();
363
364    for (const auto *foreignProp : foreignProps) {
365        auto *declNode = foreignProp->Declaration()->Node();
366        if (!declNode->IsClassProperty()) {
367            continue;
368        }
369
370        GenClassField(declNode->AsClassProperty(), classRecord, true);
371    }
372}
373
374void ETSEmitter::GenGlobalArrayRecord(checker::ETSArrayType *arrayType, checker::Signature *signature)
375{
376    std::stringstream ss;
377    arrayType->ToAssemblerTypeWithRank(ss);
378
379    auto arrayRecord = pandasm::Record(ss.str(), Program()->lang);
380
381    auto func = GenExternalFunction(signature, true);
382    func.params.emplace(func.params.begin(), pandasm::Type(ss.str(), 0), EXTENSION);
383
384    Program()->functionTable.emplace(func.name, std::move(func));
385
386    arrayRecord.metadata->SetAttribute(Signatures::EXTERNAL);
387    Program()->recordTable.emplace(arrayRecord.name, std::move(arrayRecord));
388    Program()->arrayTypes.emplace(PandasmTypeWithRank(arrayType));
389}
390
391void ETSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external)
392{
393    auto *baseType = interfaceDecl->TsType()->AsETSObjectType();
394
395    auto interfaceRecord = pandasm::Record(interfaceDecl->InternalName().Mutf8(), Program()->lang);
396
397    if (external) {
398        interfaceRecord.metadata->SetAttribute(Signatures::EXTERNAL);
399    }
400
401    uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE;
402
403    if (interfaceDecl->IsStatic()) {
404        accessFlags |= ACC_STATIC;
405    }
406
407    interfaceRecord.metadata->SetAccessFlags(accessFlags);
408    interfaceRecord.sourceFile =
409        Context()->parserProgram->VarBinder()->Program()->SourceFile().GetAbsolutePath().Mutf8();
410    interfaceRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT);
411
412    for (auto *it : baseType->Interfaces()) {
413        auto *declNode = it->GetDeclNode();
414        ASSERT(declNode->IsTSInterfaceDeclaration());
415        std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8();
416        interfaceRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name);
417    }
418
419    GenClassInheritedFields(baseType, interfaceRecord);
420
421    for (const auto *prop : interfaceDecl->Body()->Body()) {
422        if (prop->IsClassProperty()) {
423            GenClassField(prop->AsClassProperty(), interfaceRecord, external);
424        } else if (prop->IsMethodDefinition()) {
425            GenInterfaceMethodDefinition(prop->AsMethodDefinition(), external);
426        }
427    }
428
429    Program()->recordTable.emplace(interfaceRecord.name, std::move(interfaceRecord));
430}
431
432std::vector<pandasm::AnnotationData> ETSEmitter::GenAnnotations(const ir::ClassDefinition *classDef)
433{
434    std::vector<pandasm::AnnotationData> annotations;
435    const ir::AstNode *parent = classDef->Parent();
436    while (parent != nullptr) {
437        if (parent->IsMethodDefinition()) {
438            annotations.emplace_back(GenAnnotationEnclosingMethod(parent->AsMethodDefinition()));
439            annotations.emplace_back(GenAnnotationInnerClass(classDef, parent));
440            break;
441        }
442        if (parent->IsClassDefinition()) {
443            annotations.emplace_back(GenAnnotationEnclosingClass(
444                parent->AsClassDefinition()->TsType()->AsETSObjectType()->AssemblerName().Utf8()));
445            annotations.emplace_back(GenAnnotationInnerClass(classDef, parent));
446            break;
447        }
448        parent = parent->Parent();
449    }
450
451    auto classIdent = classDef->Ident()->Name().Mutf8();
452    bool isConstruct = classIdent == Signatures::JSNEW_CLASS;
453    if (isConstruct || classIdent == Signatures::JSCALL_CLASS) {
454        auto *callNames = Context()->checker->AsETSChecker()->DynamicCallNames(isConstruct);
455        annotations.push_back(GenAnnotationDynamicCall(*callNames));
456    }
457
458    return annotations;
459}
460
461static uint32_t GetAccessFlags(const ir::ClassDefinition *classDef)
462{
463    uint32_t accessFlags = ACC_PUBLIC;
464    if (classDef->IsAbstract()) {
465        accessFlags |= ACC_ABSTRACT;
466    } else if (classDef->IsFinal()) {
467        accessFlags |= ACC_FINAL;
468    }
469
470    if (classDef->IsStatic()) {
471        accessFlags |= ACC_STATIC;
472    }
473
474    return accessFlags;
475}
476
477void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool external)
478{
479    auto classRecord = pandasm::Record(classDef->InternalName().Mutf8(), Program()->lang);
480    if (external) {
481        classRecord.metadata->SetAttribute(Signatures::EXTERNAL);
482    }
483
484    uint32_t accessFlags = GetAccessFlags(classDef);
485    classRecord.metadata->SetAccessFlags(accessFlags);
486    classRecord.sourceFile = Context()->parserProgram->VarBinder()->Program()->SourceFile().GetAbsolutePath().Mutf8();
487
488    auto *baseType = classDef->TsType()->AsETSObjectType();
489    if (baseType->SuperType() != nullptr) {
490        classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE,
491                                                baseType->SuperType()->AssemblerName().Mutf8());
492    } else {
493        // NOTE: rtakacs. Replace the whole if block (below) with assert when lambda objects have super class.
494        if (baseType->AssemblerName().Mutf8() != Signatures::BUILTIN_OBJECT) {
495            classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT);
496        }
497    }
498
499    for (auto *it : baseType->Interfaces()) {
500        // We do not need to add dynamic interfaces
501        if (it->IsETSDynamicType()) {
502            continue;
503        }
504
505        auto *declNode = it->GetDeclNode();
506        // NOTE: itrubachev. replace it with ASSERT(decl_node->IsTSInterfaceDeclaration())
507        // after adding proper creation of lambda object in ETSFunctionType::AssignmentSource
508        if (!declNode->IsTSInterfaceDeclaration()) {
509            continue;
510        }
511        std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8();
512        classRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name);
513    }
514
515    GenClassInheritedFields(baseType, classRecord);
516    for (const auto *prop : classDef->Body()) {
517        if (!prop->IsClassProperty()) {
518            continue;
519        }
520
521        GenClassField(prop->AsClassProperty(), classRecord, external);
522    }
523
524    std::vector<pandasm::AnnotationData> annotations = GenAnnotations(classDef);
525    if (!annotations.empty()) {
526        classRecord.metadata->SetAnnotations(std::move(annotations));
527    }
528
529    Program()->recordTable.emplace(classRecord.name, std::move(classRecord));
530}
531
532pandasm::AnnotationData ETSEmitter::GenAnnotationSignature(const ir::ClassDefinition *classDef)
533{
534    static constexpr std::string_view OBJECT = "Lstd/core/Object";
535    std::vector<pandasm::ScalarValue> parts {};
536    std::stringstream ss {};
537    const auto &params = classDef->TypeParams()->Params();
538
539    bool firstIteration = true;
540    for (const auto *param : params) {
541        if (firstIteration) {
542            ss << Signatures::GENERIC_BEGIN;
543            firstIteration = false;
544        }
545        ss << param->Name()->Name() << Signatures::MANGLE_BEGIN;
546        parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
547
548        std::stringstream {}.swap(ss);
549        if (param->Constraint() == nullptr) {
550            ss << OBJECT;
551        } else {
552            param->Constraint()->TsType()->ToAssemblerTypeWithRank(ss);
553            auto str = ss.str();
554            std::replace(str.begin(), str.end(), *Signatures::METHOD_SEPARATOR.begin(),
555                         *Signatures::NAMESPACE_SEPARATOR.begin());
556            std::stringstream {}.swap(ss);
557            ss << Signatures::CLASS_REF_BEGIN << str << Signatures::MANGLE_SEPARATOR;
558        }
559
560        parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
561        std::stringstream {}.swap(ss);  // cleanup
562    }
563
564    ss << Signatures::GENERIC_END;
565    parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
566
567    std::stringstream {}.swap(ss);
568    if (classDef->TsType()->AsETSObjectType()->SuperType() == nullptr) {
569        ss << OBJECT;
570    } else {
571        ss << Signatures::CLASS_REF_BEGIN;
572        auto superType = classDef->TsType()->AsETSObjectType()->SuperType()->AssemblerName().Mutf8();
573        std::replace(superType.begin(), superType.end(), *Signatures::METHOD_SEPARATOR.begin(),
574                     *Signatures::NAMESPACE_SEPARATOR.begin());
575        ss << superType << Signatures::MANGLE_SEPARATOR;
576    }
577    parts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(ss.str()));
578
579    GenAnnotationRecord(Signatures::ETS_ANNOTATION_SIGNATURE);
580    pandasm::AnnotationData signature(Signatures::ETS_ANNOTATION_SIGNATURE);
581    pandasm::AnnotationElement value(
582        Signatures::ANNOTATION_KEY_VALUE,
583        std::make_unique<pandasm::ArrayValue>(pandasm::Value::Type::STRING, std::move(parts)));
584    signature.AddElement(std::move(value));
585    return signature;
586}
587
588pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef)
589{
590    GenAnnotationRecord(Signatures::ETS_ANNOTATION_ENCLOSING_METHOD);
591    pandasm::AnnotationData enclosingMethod(Signatures::ETS_ANNOTATION_ENCLOSING_METHOD);
592    pandasm::AnnotationElement value(
593        Signatures::ANNOTATION_KEY_VALUE,
594        std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::METHOD>(
595            methodDef->Function()->Scope()->InternalName().Mutf8())));
596    enclosingMethod.AddElement(std::move(value));
597    return enclosingMethod;
598}
599
600pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingClass(std::string_view className)
601{
602    GenAnnotationRecord(Signatures::ETS_ANNOTATION_ENCLOSING_CLASS);
603    pandasm::AnnotationData enclosingClass(Signatures::ETS_ANNOTATION_ENCLOSING_CLASS);
604    pandasm::AnnotationElement value(
605        Signatures::ANNOTATION_KEY_VALUE,
606        std::make_unique<pandasm::ScalarValue>(
607            pandasm::ScalarValue::Create<pandasm::Value::Type::RECORD>(pandasm::Type::FromName(className, true))));
608    enclosingClass.AddElement(std::move(value));
609    return enclosingClass;
610}
611
612pandasm::AnnotationData ETSEmitter::GenAnnotationInnerClass(const ir::ClassDefinition *classDef,
613                                                            const ir::AstNode *parent)
614{
615    GenAnnotationRecord(Signatures::ETS_ANNOTATION_INNER_CLASS);
616    pandasm::AnnotationData innerClass(Signatures::ETS_ANNOTATION_INNER_CLASS);
617    const bool isAnonymous = (classDef->Modifiers() & ir::ClassDefinitionModifiers::ANONYMOUS) != 0;
618    pandasm::AnnotationElement name(Signatures::ANNOTATION_KEY_NAME,
619                                    std::make_unique<pandasm::ScalarValue>(
620                                        isAnonymous
621                                            ? pandasm::ScalarValue::Create<pandasm::Value::Type::STRING_NULLPTR>(0)
622                                            : pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(
623                                                  classDef->TsType()->AsETSObjectType()->AssemblerName().Mutf8())));
624    innerClass.AddElement(std::move(name));
625
626    pandasm::AnnotationElement accessFlags(
627        Signatures::ANNOTATION_KEY_ACCESS_FLAGS,
628        std::make_unique<pandasm::ScalarValue>(
629            pandasm::ScalarValue::Create<pandasm::Value::Type::I32>(TranslateModifierFlags(parent->Modifiers()))));
630    innerClass.AddElement(std::move(accessFlags));
631    return innerClass;
632}
633
634ir::MethodDefinition *ETSEmitter::FindAsyncImpl(ir::ScriptFunction *asyncFunc)
635{
636    std::string implName = checker::ETSChecker::GetAsyncImplName(asyncFunc->Id()->Name());
637    ir::AstNode *ownerNode = asyncFunc->Signature()->Owner()->GetDeclNode();
638    ASSERT(ownerNode != nullptr && ownerNode->IsClassDefinition());
639    const ir::ClassDefinition *classDef = ownerNode->AsClassDefinition();
640    ASSERT(classDef != nullptr);
641
642    auto it = std::find_if(classDef->Body().rbegin(), classDef->Body().rend(), [&implName](ir::AstNode *node) {
643        return node->IsMethodDefinition() && node->AsMethodDefinition()->Id()->Name().Utf8() == implName;
644    });
645    if (it == classDef->Body().rend()) {
646        return nullptr;
647    }
648
649    ir::MethodDefinition *method = (*it)->AsMethodDefinition();
650    auto *checker = static_cast<checker::ETSChecker *>(Context()->checker);
651    checker::TypeRelation *typeRel = checker->Relation();
652    checker::SavedTypeRelationFlagsContext savedFlagsCtx(typeRel, checker::TypeRelationFlag::NO_RETURN_TYPE_CHECK);
653    method->Function()->Signature()->Compatible(typeRel, asyncFunc->Signature());
654    auto overloadIt = method->Overloads().begin();
655    while (overloadIt != method->Overloads().end() && !typeRel->IsTrue()) {
656        method = *overloadIt;
657        method->Function()->Signature()->Compatible(typeRel, asyncFunc->Signature());
658        ++overloadIt;
659    }
660    return typeRel->IsTrue() ? method : nullptr;
661}
662
663pandasm::AnnotationData ETSEmitter::GenAnnotationAsync(ir::ScriptFunction *scriptFunc)
664{
665    GenAnnotationRecord(Signatures::ETS_COROUTINE_ASYNC);
666    const ir::MethodDefinition *impl = FindAsyncImpl(scriptFunc);
667    ASSERT(impl != nullptr);
668    pandasm::AnnotationData ann(Signatures::ETS_COROUTINE_ASYNC);
669    pandasm::AnnotationElement value(
670        Signatures::ANNOTATION_KEY_VALUE,
671        std::make_unique<pandasm::ScalarValue>(pandasm::ScalarValue::Create<pandasm::Value::Type::METHOD>(
672            impl->Function()->Scope()->InternalName().Mutf8())));
673    ann.AddElement(std::move(value));
674    return ann;
675}
676
677pandasm::AnnotationData ETSEmitter::GenAnnotationDynamicCall(DynamicCallNamesMap &callNames)
678{
679    GenAnnotationRecord(Signatures::ETS_ANNOTATION_DYNAMIC_CALL);
680    pandasm::AnnotationData dynamicCallSig(Signatures::ETS_ANNOTATION_DYNAMIC_CALL);
681    std::vector<pandasm::ScalarValue> allParts {};
682    for (auto &[parts, startIdx] : callNames) {
683        startIdx = allParts.size();
684        for (const auto &str : parts) {
685            allParts.emplace_back(pandasm::ScalarValue::Create<pandasm::Value::Type::STRING>(str.Utf8()));
686        }
687    }
688    pandasm::AnnotationElement value(
689        Signatures::ANNOTATION_KEY_VALUE,
690        std::make_unique<pandasm::ArrayValue>(pandasm::Value::Type::STRING, std::move(allParts)));
691    dynamicCallSig.AddElement(std::move(value));
692    return dynamicCallSig;
693}
694
695void ETSEmitter::GenAnnotationRecord(std::string_view recordNameView, bool isRuntime, bool isType)
696{
697    const std::string recordName(recordNameView);
698    const auto recordIt = Program()->recordTable.find(recordName);
699    if (recordIt == Program()->recordTable.end()) {
700        pandasm::Record record(recordName, EXTENSION);
701        record.metadata->SetAttribute(Signatures::EXTERNAL);
702        record.metadata->SetAttribute(Signatures::ANNOTATION_ATTRIBUTE);
703        if (isRuntime && isType) {
704            record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE,
705                                               Signatures::RUNTIME_TYPE_ANNOTATION);
706        } else if (isRuntime && !isType) {
707            record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::RUNTIME_ANNOTATION);
708        } else if (!isRuntime && isType) {
709            record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::TYPE_ANNOTATION);
710        }
711        Program()->recordTable.emplace(record.name, std::move(record));
712    }
713}
714}  // namespace ark::es2panda::compiler
715