diff --git a/ets2panda/bindings/native/include/convertors-napi.h b/ets2panda/bindings/native/include/convertors-napi.h index 73e2f8682a6faf693ec543475393ddfcf60b6771..b99bade61b996a2bc0bb61ffe4b678beee2356f1 100644 --- a/ets2panda/bindings/native/include/convertors-napi.h +++ b/ets2panda/bindings/native/include/convertors-napi.h @@ -16,7 +16,7 @@ #ifndef CONVERTORS_NAPI_H_ #define CONVERTORS_NAPI_H_ -#include +#include // IWYU pragma: export #include #include #include diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp index b47ff09f704ff798f08c2f74b964a72b4f48ba63..215712fff1d03a2c2eba0d3b61de02e150ba4629 100644 --- a/ets2panda/checker/ets/utilityTypeHandlers.cpp +++ b/ets2panda/checker/ets/utilityTypeHandlers.cpp @@ -1088,7 +1088,9 @@ ir::MethodDefinition *ETSChecker::CreateNonStaticClassInitializer(varbinder::Cla VarBinder()->AsETSBinder()->BuildInternalNameWithCustomRecordTable(func, recordTable); VarBinder()->AsETSBinder()->BuildFunctionName(func); - VarBinder()->Functions().push_back(functionScope); + if (!recordTable->IsExternal()) { + VarBinder()->Functions().push_back(functionScope); + } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *funcExpr = ProgramAllocNode(func); diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index 3fd970b6bb9f95aa2d575299e3c2acd3ffbf2a89..49679056d425bbf4f018bfe93351f7b7a7c7c021 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -26,12 +26,6 @@ namespace ark::es2panda::checker { -void ETSObjectType::Iterate(const PropertyTraverser &cb) const -{ - ForEachAllOwnProperties(cb); - ForEachAllNonOwnProperties(cb); -} - void ETSObjectType::AddInterface(ETSObjectType *interfaceType) { if (std::find(interfaces_.begin(), interfaces_.end(), interfaceType) == interfaces_.end()) { @@ -426,29 +420,6 @@ varbinder::LocalVariable *ETSObjectType::CollectSignaturesForSyntheticType(std:: return nullptr; } -void ETSObjectType::ForEachAllOwnProperties(const PropertyTraverser &cb) const -{ - EnsurePropertiesInstantiated(); - for (size_t i = 0; i < static_cast(PropertyType::COUNT); ++i) { - PropertyMap &map = properties_[i]; - for (const auto &[_, prop] : map) { - (void)_; - cb(prop); - } - } -} - -void ETSObjectType::ForEachAllNonOwnProperties(const PropertyTraverser &cb) const -{ - if (superType_ != nullptr) { - superType_->Iterate(cb); - } - - for (const auto *interface : interfaces_) { - interface->Iterate(cb); - } -} - std::vector ETSObjectType::GetAllProperties() const { std::vector allProperties; @@ -543,40 +514,6 @@ std::vector ETSObjectType::Fields() const return fields; } -std::vector ETSObjectType::ForeignProperties() const -{ - std::vector foreignProps; - - // spec 9.3: all names in static and, separately, non-static class declaration scopes must be unique. - std::unordered_set ownInstanceProps; - std::unordered_set ownStaticProps; - - EnsurePropertiesInstantiated(); - ownInstanceProps.reserve(properties_.size()); - ownStaticProps.reserve(properties_.size()); - - ForEachAllOwnProperties([&](const varbinder::LocalVariable *prop) { - if (prop->HasFlag(varbinder::VariableFlags::STATIC)) { - ownStaticProps.insert(prop->Name()); - } else { - ownInstanceProps.insert(prop->Name()); - } - }); - ForEachAllNonOwnProperties([&](const varbinder::LocalVariable *var) { - if (var->HasFlag(varbinder::VariableFlags::STATIC)) { - if (ownStaticProps.find(var->Name()) == ownStaticProps.end()) { - foreignProps.push_back(var); - } - } else { - if (ownInstanceProps.find(var->Name()) == ownInstanceProps.end()) { - foreignProps.push_back(var); - } - } - }); - - return foreignProps; -} - void ETSObjectType::ToString(std::stringstream &ss, bool precise) const { if (IsPartial()) { diff --git a/ets2panda/checker/types/ets/etsObjectType.h b/ets2panda/checker/types/ets/etsObjectType.h index a86f126b974a89484f4a1ec9f5d7795a66d6a498..24558f5d5a3dc0c1170a54ad8924ab315e1a02f7 100644 --- a/ets2panda/checker/types/ets/etsObjectType.h +++ b/ets2panda/checker/types/ets/etsObjectType.h @@ -346,11 +346,8 @@ public: return name_.EndsWith(PARTIAL_CLASS_SUFFIX); } - std::vector ForeignProperties() const; varbinder::LocalVariable *GetProperty(util::StringView name, PropertySearchFlags flags) const; std::vector GetAllProperties() const; - void ForEachAllOwnProperties(const PropertyTraverser &cb) const; - void ForEachAllNonOwnProperties(const PropertyTraverser &cb) const; varbinder::LocalVariable *CopyProperty(varbinder::LocalVariable *prop, ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes); std::vector Methods() const; @@ -370,7 +367,6 @@ public: TypeRelation *relation) const; bool CheckIdenticalFlags(ETSObjectType *other) const; ETSObjectType *CreateETSObjectType(ir::AstNode *declNode, ETSObjectFlags flags); - void Iterate(const PropertyTraverser &cb) const; void ToString(std::stringstream &ss, bool precise) const override; void Identical(TypeRelation *relation, Type *other) override; bool AssignmentSource(TypeRelation *relation, Type *target) override; diff --git a/ets2panda/compiler/base/lreference.cpp b/ets2panda/compiler/base/lreference.cpp index 852eb72ba2fbe9f75eaa01bd76326b106a6a5c3c..bbd1d69bb6a81706815b77e78a6c6ff6c460ff62 100644 --- a/ets2panda/compiler/base/lreference.cpp +++ b/ets2panda/compiler/base/lreference.cpp @@ -364,12 +364,10 @@ void ETSLReference::SetValue() const return; } - const auto &propName = memberExpr->Property()->AsIdentifier()->Name(); - if (memberExpr->PropVar()->HasFlag(varbinder::VariableFlags::STATIC)) { - const util::StringView fullName = etsg_->FormClassPropReference(staticObjRef_->AsETSObjectType(), propName); + const util::StringView fullName = etsg_->FormClassPropReference(memberExpr->Property()->Variable()); + if (memberExpr->PropVar()->HasFlag(varbinder::VariableFlags::STATIC)) { etsg_->StoreStaticProperty(Node(), memberExprTsType, fullName); - return; } @@ -381,7 +379,7 @@ void ETSLReference::SetValue() const const auto *type = memberExpr->PropVar()->TsType(); - etsg_->StoreProperty(Node(), type, baseReg_, propName); + etsg_->StoreProperty(Node(), type, baseReg_, fullName); } } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index fc921010efd67abd01808af32ff58f76ca59f6a1..897b87481613d5d976b1daede86fe5531926683b 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -63,10 +63,11 @@ void ETSCompiler::Compile(const ir::ClassProperty *st) const etsg->ApplyConversion(st->Value(), st->TsType()); } + auto fullName = etsg->FormClassOwnPropReference(etsg->ContainingObjectType(), st->Key()->AsIdentifier()->Name()); if (st->IsStatic()) { - etsg->StoreStaticOwnProperty(st, st->TsType(), st->Key()->AsIdentifier()->Name()); + etsg->StoreStaticProperty(st, st->TsType(), fullName); } else { - etsg->StoreProperty(st, st->TsType(), etsg->GetThisReg(), st->Key()->AsIdentifier()->Name()); + etsg->StoreProperty(st, st->TsType(), etsg->GetThisReg(), fullName); } } @@ -93,7 +94,7 @@ void ETSCompiler::Compile(const ir::ETSClassLiteral *expr) const etsg->SetAccumulatorType(literalType); } - etsg->GetType(expr, isPrimitive); + etsg->EmitLdaType(expr, etsg->GetAccumulatorType()->AsETSObjectType()->AssemblerName()); ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType())); } @@ -937,7 +938,6 @@ void ETSCompiler::Compile(const ir::MemberExpression *expr) const } auto *const objectType = etsg->Checker()->GetApparentType(expr->Object()->TsType()); - auto &propName = expr->Property()->AsIdentifier()->Name(); auto ottctx = compiler::TargetTypeContext(etsg, expr->Object()->TsType()); etsg->CompileAndCheck(expr->Object()); @@ -959,22 +959,7 @@ void ETSCompiler::Compile(const ir::MemberExpression *expr) const } else if (objectType->IsETSUnionType()) { etsg->LoadPropertyByName(expr, objReg, checker::ETSChecker::FormNamedAccessMetadata(expr->PropVar())); } else { - auto *id = expr->Property()->AsIdentifier(); - auto *var = id->Variable(); - ES2PANDA_ASSERT(var != nullptr && var->Declaration() != nullptr); - - auto *decl = var->Declaration(); - ES2PANDA_ASSERT(decl->Node() != nullptr); - - auto *declNode = decl->Node(); - ES2PANDA_ASSERT(declNode->Parent() != nullptr && declNode->Parent()->IsTyped()); - - auto *typedOwner = declNode->Parent()->AsTyped(); - const checker::Type *expectedObjType = typedOwner->TsType(); - ES2PANDA_ASSERT(expectedObjType != nullptr && expectedObjType->IsETSObjectType()); - - const auto fullName = etsg->FormClassPropReference(expectedObjType->AsETSObjectType(), propName); - etsg->LoadProperty(expr, variableType, objReg, fullName); + etsg->LoadProperty(expr, variableType, objReg, etsg->FormClassPropReference(expr->PropVar())); } etsg->GuardUncheckedType(expr, expr->UncheckedType(), expr->TsType()); @@ -1012,8 +997,7 @@ bool ETSCompiler::HandleStaticProperties(const ir::MemberExpression *expr, ETSGe etsg->CallExact(expr, sig->InternalName()); etsg->SetAccumulatorType(expr->TsType()); } else { - util::StringView const fullName = - etsg->FormClassPropReference(expr->Object()->TsType()->AsETSObjectType(), variable->Name()); + util::StringView const fullName = etsg->FormClassPropReference(variable); etsg->LoadStaticProperty(expr, varType, fullName); etsg->ApplyConversion(expr, expr->TsType()); } @@ -1059,7 +1043,7 @@ void ETSCompiler::Compile(const ir::ObjectExpression *expr) const value->Compile(etsg); etsg->ApplyConversion(value, key->TsType()); - etsg->StoreProperty(expr, key->TsType(), objReg, pname); + etsg->StoreProperty(expr, key->TsType(), objReg, etsg->FormClassPropReference(prop->Variable())); } etsg->LoadAccumulator(expr, objReg); diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index bd09f10ff1bd697d8165bce7941c4439d09ecde6..a57b3008e1008d8123e14fbf635cf7f3a7f09885 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -13,9 +13,13 @@ * limitations under the License. */ +#include #include "ETSGen-inl.h" +#include "assembler/mangling.h" +#include "compiler/core/ETSemitter.h" #include "compiler/core/codeGen.h" +#include "compiler/core/emitter.h" #include "compiler/core/regScope.h" #include "generated/isa.h" #include "generated/signatures.h" @@ -120,6 +124,11 @@ const checker::ETSObjectType *ETSGen::ContainingObjectType() const noexcept return containingObjectType_; } +ETSEmitter *ETSGen::Emitter() const +{ + return static_cast(Context()->emitter); +} + VReg &ETSGen::Acc() noexcept { return acc_; @@ -248,14 +257,12 @@ void ETSGen::LoadVar(const ir::Identifier *node, varbinder::Variable const *cons switch (ETSLReference::ResolveReferenceKind(var)) { case ReferenceKind::STATIC_FIELD: { - auto fullName = FormClassPropReference(var); - LoadStaticProperty(node, var->TsType(), fullName); + LoadStaticProperty(node, var->TsType(), FormClassPropReference(var)); break; } case ReferenceKind::FIELD: { ES2PANDA_ASSERT(GetVRegType(GetThisReg()) != nullptr); - const auto fullName = FormClassPropReference(GetVRegType(GetThisReg())->AsETSObjectType(), var->Name()); - LoadProperty(node, var->TsType(), GetThisReg(), fullName); + LoadProperty(node, var->TsType(), GetThisReg(), FormClassPropReference(var)); break; } case ReferenceKind::METHOD: @@ -283,12 +290,11 @@ void ETSGen::StoreVar(const ir::Identifier *node, const varbinder::ConstScopeFin switch (ETSLReference::ResolveReferenceKind(result.variable)) { case ReferenceKind::STATIC_FIELD: { - auto fullName = FormClassPropReference(result.variable); - StoreStaticProperty(node, result.variable->TsType(), fullName); + StoreStaticProperty(node, result.variable->TsType(), FormClassPropReference(result.variable)); break; } case ReferenceKind::FIELD: { - StoreProperty(node, result.variable->TsType(), GetThisReg(), result.name); + StoreProperty(node, result.variable->TsType(), GetThisReg(), FormClassPropReference(result.variable)); break; } case ReferenceKind::LOCAL: { @@ -302,25 +308,40 @@ void ETSGen::StoreVar(const ir::Identifier *node, const varbinder::ConstScopeFin } } -util::StringView ETSGen::FormClassPropReference(const checker::ETSObjectType *classType, const util::StringView &name) +util::StringView ETSGen::AssemblerReference(util::StringView ref) +{ + Emitter()->AddDependence(ref.Mutf8()); + return ref; +} + +util::StringView ETSGen::AssemblerSignatureReference(util::StringView ref) +{ + auto const funcName = pandasm::GetFunctionNameFromSignature(std::string(ref)); + ES2PANDA_ASSERT(!funcName.empty()); + auto const className = funcName.substr(0, funcName.rfind('.')); + AssemblerReference(util::StringView(className)); + + return AssemblerReference(ref); +} + +util::StringView ETSGen::AssemblerReference(checker::Signature const *sig) +{ + return AssemblerSignatureReference(sig->InternalName()); // simplify +} + +util::StringView ETSGen::FormClassOwnPropReference(const checker::ETSObjectType *classType, + const util::StringView &name) { std::stringstream ss; ES2PANDA_ASSERT(classType != nullptr); - ss << classType->AssemblerName().Mutf8() << Signatures::METHOD_SEPARATOR << name; - return util::StringView(*ProgElement()->Strings().emplace(ss.str()).first); + ss << ToAssemblerType(classType) << Signatures::METHOD_SEPARATOR << name; + return util::StringView(*ProgElement()->Strings().emplace(Emitter()->AddDependence(ss.str())).first); } util::StringView ETSGen::FormClassPropReference(varbinder::Variable const *const var) { auto containingObjectType = util::Helpers::GetContainingObjectType(var->Declaration()->Node()); - return FormClassPropReference(containingObjectType, var->Name()); -} - -void ETSGen::StoreStaticOwnProperty(const ir::AstNode *node, const checker::Type *propType, - const util::StringView &name) -{ - util::StringView fullName = FormClassPropReference(containingObjectType_, name); - StoreStaticProperty(node, propType, fullName); + return FormClassOwnPropReference(containingObjectType, var->Name()); } void ETSGen::StoreStaticProperty(const ir::AstNode *const node, const checker::Type *propType, @@ -369,12 +390,8 @@ void ETSGen::LoadStaticProperty(const ir::AstNode *const node, const checker::Ty } void ETSGen::StoreProperty(const ir::AstNode *const node, const checker::Type *propType, const VReg objReg, - const util::StringView &name) + const util::StringView &fullName) { - ES2PANDA_ASSERT(Checker()->GetApparentType(GetVRegType(objReg)) != nullptr); - auto *objType = Checker()->GetApparentType(GetVRegType(objReg))->AsETSObjectType(); - const auto fullName = FormClassPropReference(objType, name); - if (propType->IsETSReferenceType()) { Ra().Emit(node, objReg, fullName); } else if (IsWidePrimitiveType(propType)) { @@ -419,7 +436,7 @@ void ETSGen::StorePropertyByName([[maybe_unused]] const ir::AstNode *node, [[may { #ifdef PANDA_WITH_ETS auto [metaObj, propType, propName] = fieldMeta; - const auto fullName = FormClassPropReference(metaObj, propName); + const auto fullName = FormClassOwnPropReference(metaObj, propName); if (propType->IsETSReferenceType()) { Ra().Emit(node, objReg, fullName); @@ -438,7 +455,7 @@ void ETSGen::LoadPropertyByName([[maybe_unused]] const ir::AstNode *const node, { #ifdef PANDA_WITH_ETS auto [metaObj, propType, propName] = fieldMeta; - const auto fullName = FormClassPropReference(metaObj, propName); + const auto fullName = FormClassOwnPropReference(metaObj, propName); if (propType->IsETSReferenceType()) { Ra().Emit(node, objReg, fullName); @@ -511,7 +528,7 @@ void ETSGen::CallRangeFillUndefined(const ir::AstNode *const node, checker::Sign for (size_t idx = 0; idx < signature->ArgCount(); idx++) { Ra().Emit(node, AllocReg(), undef); } - Rra().Emit(node, argStart, signature->ArgCount() + 1, signature->InternalName(), argStart); + Rra().Emit(node, argStart, signature->ArgCount() + 1, AssemblerReference(signature), argStart); } void ETSGen::LoadThis(const ir::AstNode *node) @@ -521,7 +538,7 @@ void ETSGen::LoadThis(const ir::AstNode *node) void ETSGen::CreateBigIntObject(const ir::AstNode *node, VReg arg0, std::string_view signature) { - Ra().Emit(node, signature, arg0, dummyReg_); + Ra().Emit(node, AssemblerSignatureReference(signature), arg0, dummyReg_); } VReg ETSGen::GetThisReg() const @@ -833,7 +850,8 @@ void ETSGen::EmitFailedTypeCastException(const ir::AstNode *node, const VReg src } SetVRegType(errorReg, Checker()->GlobalETSBooleanType()); LoadAccumulatorString(node, util::UString(target->ToString(), Allocator()).View()); - Ra().Emit(node, Signatures::BUILTIN_RUNTIME_FAILED_TYPE_CAST_EXCEPTION, src, errorReg, dummyReg_, 1); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_RUNTIME_FAILED_TYPE_CAST_EXCEPTION), + src, errorReg, dummyReg_, 1); StoreAccumulator(node, errorReg); EmitThrow(node, errorReg); SetAccumulatorType(nullptr); @@ -1571,7 +1589,7 @@ void ETSGen::ResolveConditionalResultReference(const ir::AstNode *node) StoreAccumulator(node, objReg); ES2PANDA_ASSERT(Checker()->GlobalBuiltinETSStringType() != nullptr); - EmitIsInstance(node, Checker()->GlobalBuiltinETSStringType()->AssemblerName()); + EmitIsInstance(node, ToAssemblerType(Checker()->GlobalBuiltinETSStringType())); BranchIfTrue(node, isString); Sa().Emit(node, 1); Branch(node, end); @@ -1965,7 +1983,7 @@ void ETSGen::HandlePossiblyNullishEquality(const ir::AstNode *node, VReg lhs, VR } static std::optional> SelectLooseObjComparator( - checker::ETSChecker *checker, checker::Type *lhs, checker::Type *rhs) + checker::ETSChecker *checker, checker::Type *lhs, checker::Type *rhs, ETSEmitter *emitter) { auto alhs = checker->GetApparentType(checker->GetNonNullishType(lhs)); auto arhs = checker->GetApparentType(checker->GetNonNullishType(rhs)); @@ -1984,8 +2002,9 @@ static std::optional> SelectL return std::nullopt; } // NOTE(vpukhov): emit faster code - auto methodSig = - util::UString(std::string(obj->AssemblerName()) + ".equals:std.core.Object;u1;", checker->Allocator()).View(); + auto methodSig = util::UString(emitter->AddDependence(obj->AssemblerName().Mutf8()) + ".equals:std.core.Object;u1;", + checker->Allocator()) + .View(); return std::make_pair(checker->GetNonConstantType(obj), methodSig); } @@ -2051,8 +2070,9 @@ void ETSGen::RefEqualityLoose(const ir::AstNode *node, VReg lhs, VReg rhs, Label } else if (auto spec = SelectLooseObjComparator( // try to select specific type // CC-OFFNXT(G.FMT.06-CPP) project code style const_cast(Checker()), const_cast(ltype), - const_cast(rtype)); // CC-OFF(G.FMT.02) project code style - spec.has_value()) { // CC-OFF(G.FMT.02-CPP) project code style + const_cast(rtype), // CC-OFF(G.FMT.02) project code style + Emitter()); + spec.has_value()) { // CC-OFF(G.FMT.02-CPP) project code style auto ifTrue = AllocLabel(); if (ltype->PossiblyETSNullish() || rtype->PossiblyETSNullish()) { HandlePossiblyNullishEquality(node, lhs, rhs, ifFalse, ifTrue); @@ -2408,7 +2428,8 @@ void ETSGen::StringBuilderAppend(const ir::AstNode *node, VReg builder) Label *ifUndefined = AllocLabel(); Label *end = AllocLabel(); BranchIfUndefined(node, ifUndefined); - Ra().Emit(node, Signatures::BUILTIN_OBJECT_TO_STRING, dummyReg_, 0); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_OBJECT_TO_STRING), + dummyReg_, 0); JumpTo(node, end); SetLabel(node, ifUndefined); @@ -2416,7 +2437,8 @@ void ETSGen::StringBuilderAppend(const ir::AstNode *node, VReg builder) SetLabel(node, end); } else { - Ra().Emit(node, Signatures::BUILTIN_OBJECT_TO_STRING, dummyReg_, 0); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_OBJECT_TO_STRING), + dummyReg_, 0); } } @@ -2466,7 +2488,8 @@ void ETSGen::CreateStringBuilder(const ir::Expression *node) { RegScope rs(this); - Ra().Emit(node, Signatures::BUILTIN_STRING_BUILDER_CTOR, dummyReg_, dummyReg_); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_STRING_BUILDER_CTOR), dummyReg_, + dummyReg_); SetAccumulatorType(Checker()->GlobalStringBuilderBuiltinType()); auto builder = AllocReg(); @@ -2514,7 +2537,8 @@ void ETSGen::AppendTemplateString(const ir::TemplateLiteral *node) { RegScope rs(this); - Ra().Emit(node, Signatures::BUILTIN_STRING_BUILDER_CTOR, dummyReg_, dummyReg_); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_STRING_BUILDER_CTOR), dummyReg_, + dummyReg_); SetAccumulatorType(Checker()->GlobalStringBuilderBuiltinType()); auto builder = AllocReg(); @@ -2594,23 +2618,22 @@ void ETSGen::ConcatTemplateString(const ir::TemplateLiteral *node) void ETSGen::NewObject(const ir::AstNode *const node, const util::StringView name, VReg athis) { - Ra().Emit(node, athis, name); + Ra().Emit(node, athis, AssemblerReference(name)); SetVRegType(athis, Checker()->GlobalETSObjectType()); } void ETSGen::NewArray(const ir::AstNode *const node, const VReg arr, const VReg dim, const checker::Type *const arrType) { - std::stringstream ss; - arrType->ToAssemblerTypeWithRank(ss); - const auto res = ProgElement()->Strings().emplace(ss.str()); + auto str = ToAssemblerType(arrType); + const auto res = ProgElement()->Strings().emplace(str); - Ra().Emit(node, arr, dim, util::StringView(*res.first)); + Ra().Emit(node, arr, dim, AssemblerReference(util::StringView(*res.first))); SetVRegType(arr, arrType); } void ETSGen::LoadResizableArrayLength(const ir::AstNode *node) { - Ra().Emit(node, Signatures::BUILTIN_ARRAY_LENGTH, dummyReg_, 0); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_ARRAY_LENGTH), dummyReg_, 0); SetAccumulatorType(Checker()->GlobalIntType()); } @@ -2619,7 +2642,8 @@ void ETSGen::LoadResizableArrayElement(const ir::AstNode *node, const VReg arrOb auto *vRegType = GetVRegType(arrObj); ES2PANDA_ASSERT(vRegType != nullptr); auto *elementType = vRegType->AsETSResizableArrayType()->ElementType(); - Ra().Emit(node, Signatures::BUILTIN_ARRAY_GET_ELEMENT, arrObj, arrIndex); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_ARRAY_GET_ELEMENT), arrObj, + arrIndex); SetAccumulatorType(elementType); } @@ -2729,8 +2753,8 @@ void ETSGen::LoadTupleElement(const ir::AstNode *node, VReg objectReg, const che std::size_t index) { ES2PANDA_ASSERT(GetVRegType(objectReg) != nullptr && GetVRegType(objectReg)->IsETSTupleType()); - const auto propName = FormClassPropReference(GetVRegType(objectReg)->AsETSTupleType()->GetWrapperType(), - GetTupleMemberNameForIndex(index)); + const auto propName = FormClassOwnPropReference(GetVRegType(objectReg)->AsETSTupleType()->GetWrapperType(), + GetTupleMemberNameForIndex(index)); // NOTE (smartin): remove after generics without type erasure is possible const auto *const boxedElementType = Checker()->MaybeBoxType(elementType); @@ -2743,10 +2767,11 @@ void ETSGen::StoreTupleElement(const ir::AstNode *node, VReg objectReg, const ch ES2PANDA_ASSERT(GetVRegType(objectReg) != nullptr && GetVRegType(objectReg)->IsETSTupleType()); const auto *const tupleType = GetVRegType(objectReg)->AsETSTupleType(); SetVRegType(objectReg, tupleType->GetWrapperType()); + const auto fullName = FormClassOwnPropReference(tupleType->GetWrapperType(), GetTupleMemberNameForIndex(index)); // NOTE (smartin): remove after generics without type erasure is possible const auto *const boxedElementType = Checker()->MaybeBoxType(elementType); - StoreProperty(node, boxedElementType, objectReg, GetTupleMemberNameForIndex(index)); + StoreProperty(node, boxedElementType, objectReg, fullName); } template @@ -2785,28 +2810,28 @@ template void ETSGen::IncrementImmediateRegister(const ir::AstNode *nod void ETSGen::LoadStringLength(const ir::AstNode *node) { - Ra().Emit(node, Signatures::BUILTIN_STRING_LENGTH, dummyReg_, 0); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_STRING_LENGTH), dummyReg_, 0); SetAccumulatorType(Checker()->GlobalIntType()); } void ETSGen::FloatIsNaN(const ir::AstNode *node) { - Ra().Emit(node, Signatures::BUILTIN_FLOAT_IS_NAN, dummyReg_, 0); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_FLOAT_IS_NAN), dummyReg_, 0); SetAccumulatorType(Checker()->GlobalETSBooleanType()); } void ETSGen::DoubleIsNaN(const ir::AstNode *node) { - Ra().Emit(node, Signatures::BUILTIN_DOUBLE_IS_NAN, dummyReg_, 0); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_DOUBLE_IS_NAN), dummyReg_, 0); SetAccumulatorType(Checker()->GlobalETSBooleanType()); } void ETSGen::LoadStringChar(const ir::AstNode *node, const VReg stringObj, const VReg charIndex, bool needBox) { - Ra().Emit(node, Signatures::BUILTIN_STRING_CHAR_AT, stringObj, charIndex); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_STRING_CHAR_AT), stringObj, charIndex); SetAccumulatorType(Checker()->GlobalCharType()); if (needBox) { - Ra().Emit(node, Signatures::BUILTIN_CHAR_VALUE_OF, dummyReg_, 0); + Ra().Emit(node, AssemblerSignatureReference(Signatures::BUILTIN_CHAR_VALUE_OF), dummyReg_, 0); SetAccumulatorType(Checker()->GlobalCharBuiltinType()); } } @@ -2882,7 +2907,9 @@ util::StringView ETSGen::ToAssemblerType(const es2panda::checker::Type *type) co std::stringstream ss; type->ToAssemblerTypeWithRank(ss); - return util::UString(ss.str(), Allocator()).View(); + auto const str = ss.str(); + Emitter()->AddDependence(str); + return util::UString(str, Allocator()).View(); } template diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index 72d720e5216e98efc35aa57cdd3f60289616e6b5..44062c41cc13294f29efe3e31854726d9f54fa0d 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -16,6 +16,12 @@ #ifndef ES2PANDA_COMPILER_CORE_ETSGEN_H #define ES2PANDA_COMPILER_CORE_ETSGEN_H +#include +#include +#include +#include + +#include "compiler/core/ETSemitter.h" #include "ir/astNode.h" #include "compiler/core/codeGen.h" #include "compiler/core/ETSfunction.h" @@ -23,7 +29,6 @@ #include "checker/ETSchecker.h" #include "ir/expressions/identifier.h" #include "util/helpers.h" -#include namespace ark::es2panda::compiler { @@ -36,6 +41,7 @@ public: [[nodiscard]] const varbinder::ETSBinder *VarBinder() const noexcept; [[nodiscard]] const checker::Type *ReturnType() const noexcept; [[nodiscard]] const checker::ETSObjectType *ContainingObjectType() const noexcept; + ETSEmitter *Emitter() const; [[nodiscard]] VReg &Acc() noexcept; [[nodiscard]] VReg Acc() const noexcept; @@ -61,9 +67,9 @@ public: void LoadStaticProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &fullName); void StoreStaticProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &fullName); - void StoreStaticOwnProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &name); - [[nodiscard]] util::StringView FormClassPropReference(const checker::ETSObjectType *classType, - const util::StringView &name); + [[nodiscard]] util::StringView FormClassPropReference(varbinder::Variable const *var); + [[nodiscard]] util::StringView FormClassOwnPropReference(const checker::ETSObjectType *classType, + const util::StringView &name); void StoreProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, const util::StringView &name); @@ -373,23 +379,23 @@ public: void CallExact(const ir::AstNode *const node, const util::StringView name) { - Ra().Emit(node, name, dummyReg_, dummyReg_); + Ra().Emit(node, AssemblerSignatureReference(name), dummyReg_, dummyReg_); } void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0) { - Ra().Emit(node, name, arg0, dummyReg_); + Ra().Emit(node, AssemblerSignatureReference(name), arg0, dummyReg_); } void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0, const VReg arg1) { - Ra().Emit(node, name, arg0, arg1); + Ra().Emit(node, AssemblerSignatureReference(name), arg0, arg1); } void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0, const VReg arg1, const VReg arg2) { - Ra().Emit(node, name, arg0, arg1, arg2, dummyReg_); + Ra().Emit(node, AssemblerSignatureReference(name), arg0, arg1, arg2, dummyReg_); } void CallByName([[maybe_unused]] const ir::AstNode *const node, @@ -436,12 +442,12 @@ public: void CallVirtual(const ir::AstNode *const node, const util::StringView name, const VReg athis) { - Ra().Emit(node, name, athis, dummyReg_); + Ra().Emit(node, AssemblerSignatureReference(name), athis, dummyReg_); } void CallVirtual(const ir::AstNode *const node, const util::StringView name, const VReg athis, const VReg arg0) { - Ra().Emit(node, name, athis, arg0); + Ra().Emit(node, AssemblerSignatureReference(name), athis, arg0); } struct CallDynamicData { @@ -484,20 +490,9 @@ public: void CreateBigIntObject(const ir::AstNode *node, VReg arg0, std::string_view signature = Signatures::BUILTIN_BIGINT_CTOR); - void GetType(const ir::AstNode *node, bool isEtsPrimitive) - { - if (isEtsPrimitive) { - // NOTE: SzD. LoadStaticProperty if ETS stdlib has static TYPE constants otherwise fallback to LdaType - } else { - ES2PANDA_ASSERT(GetAccumulatorType() != nullptr); - auto classRef = GetAccumulatorType()->AsETSObjectType()->AssemblerName(); - Sa().Emit(node, classRef); - } - } - void EmitLdaType(const ir::AstNode *node, util::StringView sv) { - Sa().Emit(node, sv); + Sa().Emit(node, AssemblerReference(sv)); } ~ETSGen() override = default; @@ -507,6 +502,12 @@ public: private: const VReg dummyReg_ = VReg::RegStart(); + util::StringView AssemblerReference(util::StringView ref); + + util::StringView AssemblerSignatureReference(util::StringView ref); + + util::StringView AssemblerReference(checker::Signature const *sig); + void LoadConstantObject(const ir::Expression *node, const checker::Type *type); void CreateStringBuilder(const ir::Expression *node); void StringBuilderAppend(const ir::AstNode *node, VReg builder); @@ -514,7 +515,6 @@ private: void StringBuilder(const ir::Expression *left, const ir::Expression *right, VReg builder); void AppendTemplateString(const ir::TemplateLiteral *node); void ConcatTemplateString(const ir::TemplateLiteral *node); - util::StringView FormClassPropReference(varbinder::Variable const *var); void UnaryMinus(const ir::AstNode *node); void UnaryTilde(const ir::AstNode *node); @@ -542,14 +542,14 @@ private: void EmitCheckCast(const ir::AstNode *node, util::StringView target) { if (target != Signatures::BUILTIN_OBJECT) { - Sa().Emit(node, target); + Sa().Emit(node, AssemblerReference(target)); } } void EmitIsInstance(const ir::AstNode *node, util::StringView target) { if (target != Signatures::BUILTIN_OBJECT) { - Sa().Emit(node, target); + Sa().Emit(node, AssemblerReference(target)); } else { LoadAccumulatorBoolean(node, true); } @@ -647,7 +647,7 @@ private: const ArenaVector &arguments) { RegScope rs(this); - const auto name = signature->InternalName(); + const auto name = AssemblerReference(signature); switch (arguments.size()) { case 0U: { @@ -689,28 +689,29 @@ private: { ES2PANDA_ASSERT(signature != nullptr); RegScope rs(this); + auto name = AssemblerReference(signature); switch (arguments.size()) { case 0U: { - Ra().Emit(node, signature->InternalName(), dummyReg_, dummyReg_); + Ra().Emit(node, name, dummyReg_, dummyReg_); break; } case 1U: { COMPILE_ARG(0); - Ra().Emit(node, signature->InternalName(), arg0, dummyReg_); + Ra().Emit(node, name, arg0, dummyReg_); break; } case 2U: { COMPILE_ARG(0); COMPILE_ARG(1); - Ra().Emit(node, signature->InternalName(), arg0, arg1); + Ra().Emit(node, name, arg0, arg1); break; } case 3U: { COMPILE_ARG(0); COMPILE_ARG(1); COMPILE_ARG(2); - Ra().Emit(node, signature->InternalName(), arg0, arg1, arg2, dummyReg_); + Ra().Emit(node, name, arg0, arg1, arg2, dummyReg_); break; } case 4U: { @@ -718,7 +719,7 @@ private: COMPILE_ARG(1); COMPILE_ARG(2); COMPILE_ARG(3); - Ra().Emit(node, signature->InternalName(), arg0, arg1, arg2, arg3); + Ra().Emit(node, name, arg0, arg1, arg2, arg3); break; } default: { @@ -728,7 +729,7 @@ private: COMPILE_ARG(idx); } - Rra().Emit(node, argStart, arguments.size(), signature->InternalName(), argStart); + Rra().Emit(node, argStart, arguments.size(), name, argStart); break; } } @@ -751,7 +752,7 @@ private: const ArenaVector &arguments) { RegScope rs(this); - const auto name = signature->InternalName(); + const auto name = AssemblerReference(signature); switch (arguments.size()) { case 0U: { @@ -785,7 +786,7 @@ private: const ArenaVector &arguments) { RegScope rs(this); - const auto name = signature->InternalName(); + const auto name = AssemblerReference(signature); switch (arguments.size()) { case 0U: { diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index de105630af76aae36079948cf88f3a910ca8178c..dac6db2fa7e14fc2066143ee6e5a39ae2925d856 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -15,8 +15,18 @@ #include "ETSemitter.h" +#include +#include +#include +#include +#include +#include +#include + #include "annotation.h" +#include "compiler/base/catchTable.h" #include "compiler/core/ETSGen.h" +#include "util/es2pandaMacros.h" #include "varbinder/varbinder.h" #include "varbinder/ETSBinder.h" #include "ir/astNode.h" @@ -29,7 +39,6 @@ #include "ir/statements/annotationDeclaration.h" #include "ir/ts/tsInterfaceDeclaration.h" #include "ir/ts/tsInterfaceBody.h" -#include "ir/ts/tsTypeParameterDeclaration.h" #include "ir/ts/tsTypeParameter.h" #include "ir/typeNode.h" #include "parser/program/program.h" @@ -38,17 +47,12 @@ #include "checker/ETSchecker.h" #include "checker/types/type.h" #include "checker/types/gradualType.h" -#include "checker/types/ets/types.h" #include "checker/types/ets/etsPartialTypeParameter.h" #include "public/public.h" #include "util/nameMangler.h" #include "assembly-program.h" -namespace { -uint32_t g_litArrayValueCount = 0; -} // namespace - namespace ark::es2panda::compiler { #ifdef PANDA_WITH_ETS @@ -95,52 +99,118 @@ static uint32_t TranslateModifierFlags(ir::ModifierFlags modifierFlags) return accessFlags; } -static pandasm::Type PandasmTypeWithRank(checker::Type const *type, uint32_t rank = 0) +namespace detail { +static constexpr bool OPTIMIZE = true; + +static const std::set RECORDS_FOR_COMPILER_OPTIMIZATION { + "std.core.String", "std.core.String[]", "std.core.Object", "std.core.Object[]", "std.core.StringBuilder", +}; + +class EmitterDependencies final { +public: + explicit EmitterDependencies() = default; + NO_COPY_SEMANTIC(EmitterDependencies); + NO_MOVE_SEMANTIC(EmitterDependencies); + + std::string AddDependence(std::string str) + { + reachable_.insert(str); + return str; + } + + bool IsNotRequired(std::string str, bool isExternal) + { + if (!OPTIMIZE) { + return false; + } + if (isExternal) { + return toEmit_.find(str) == toEmit_.end(); + } + AddDependence(str); + return false; + } + + bool IsNotRequired(std::string str) + { + return IsNotRequired(std::move(str), true); + } + + void ProcessToEmission() + { + toEmit_ = reachable_; + } + + void ProceedToMissingRecord() + { + if (reachable_.size() == toEmit_.size()) { + toEmit_.clear(); + return; + } + + std::unordered_set diff; + + for (auto &e : reachable_) { + if (toEmit_.find(e) == toEmit_.end()) { + diff.insert(e); + } + } + std::swap(toEmit_, diff); + } + +private: + std::unordered_set reachable_ { + RECORDS_FOR_COMPILER_OPTIMIZATION.begin(), + RECORDS_FOR_COMPILER_OPTIMIZATION.end(), + }; + std::unordered_set toEmit_ {}; +}; + +} // namespace detail + +static pandasm::Type PandasmTypeWithRank(ETSEmitter *emitter, checker::Type const *type) { if (type->IsGradualType()) { - return PandasmTypeWithRank(type->AsGradualType()->GetBaseType()); + return PandasmTypeWithRank(emitter, type->AsGradualType()->GetBaseType()); } if (type->IsETSTypeParameter()) { - return PandasmTypeWithRank(type->AsETSTypeParameter()->GetConstraintType()); + return PandasmTypeWithRank(emitter, type->AsETSTypeParameter()->GetConstraintType()); } if (type->IsETSNonNullishType()) { - return PandasmTypeWithRank(type->AsETSNonNullishType()->GetUnderlying()); + return PandasmTypeWithRank(emitter, type->AsETSNonNullishType()->GetUnderlying()); } if (type->IsETSPartialTypeParameter()) { - return PandasmTypeWithRank(type->AsETSPartialTypeParameter()->GetUnderlying()); + return PandasmTypeWithRank(emitter, type->AsETSPartialTypeParameter()->GetUnderlying()); } - std::stringstream ss; - type->ToAssemblerType(ss); - return pandasm::Type(ss.str(), rank == 0 ? type->Rank() : rank); + auto asmType = type->ToAssemblerType(); + auto res = pandasm::Type(asmType, type->Rank()); + if (res.IsObject() && !(res.IsArray() || res.IsUnion())) { + emitter->AddDependence(asmType); + } + return res; } -static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc, ETSEmitter *emitter) +static std::string ToAssemblerSignature(ir::ScriptFunction const *func) { - auto *funcScope = scriptFunc->Scope(); - auto *paramScope = funcScope->ParamScope(); - - auto func = pandasm::Function(funcScope->InternalName().Mutf8(), EXTENSION); - func.params.reserve(paramScope->Params().size()); + return func->Scope()->InternalName().Mutf8(); +} - for (const auto *var : paramScope->Params()) { - func.params.emplace_back(PandasmTypeWithRank(var->TsType()), EXTENSION); - if (scriptFunc->IsExternal() || var->Declaration()->Node() == nullptr || - !var->Declaration()->Node()->IsETSParameterExpression()) { - continue; - } - if (var->Declaration()->Node()->AsETSParameterExpression()->HasAnnotations()) { - func.params.back().GetOrCreateMetadata()->SetAnnotations(emitter->GenCustomAnnotations( - var->Declaration()->Node()->AsETSParameterExpression()->Annotations(), var->Name().Mutf8())); - } +static std::string ToAssemblerType(ir::AstNode const *node) +{ + if (node->IsClassDefinition()) { + return node->AsClassDefinition()->InternalName().Mutf8(); } - - if (scriptFunc->IsConstructor() || scriptFunc->IsStaticBlock()) { - func.returnType = pandasm::Type(Signatures::PRIMITIVE_VOID, 0); - } else { - func.returnType = PandasmTypeWithRank(scriptFunc->Signature()->ReturnType()); + if (node->IsTSInterfaceDeclaration()) { + return node->AsTSInterfaceDeclaration()->InternalName().Mutf8(); } + if (node->IsAnnotationDeclaration()) { + return node->AsAnnotationDeclaration()->InternalName().Mutf8(); + } + ES2PANDA_UNREACHABLE(); +} +static uint32_t ComputeAccessFlags(const ir::ScriptFunction *scriptFunc) +{ uint32_t accessFlags = 0; if (!scriptFunc->IsStaticBlock()) { const auto *methodDef = util::Helpers::GetContainingClassMethodDefinition(scriptFunc); @@ -150,25 +220,82 @@ static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc, if (scriptFunc->HasRestParameter()) { accessFlags |= ACC_VARARGS; } - func.metadata->SetAccessFlags(accessFlags); - if (!scriptFunc->IsExternal() && scriptFunc->HasAnnotations()) { - func.metadata->SetAnnotations(emitter->GenCustomAnnotations(scriptFunc->Annotations(), func.name)); + if (!scriptFunc->HasBody() && scriptFunc->Signature()->Owner()->HasObjectFlag(checker::ETSObjectFlags::INTERFACE)) { + accessFlags |= ACC_ABSTRACT; + } + return accessFlags; +} + +static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc, ETSEmitter *emitter, bool external) +{ + auto *paramScope = scriptFunc->Scope()->ParamScope(); + + ES2PANDA_ASSERT(ToAssemblerSignature(scriptFunc).find("fault.C.") == std::string::npos); + auto func = pandasm::Function(ToAssemblerSignature(scriptFunc), EXTENSION); + func.params.reserve(paramScope->Params().size()); + + for (const auto *var : paramScope->Params()) { + func.params.emplace_back(PandasmTypeWithRank(emitter, var->TsType()), EXTENSION); + if (!external && var->Declaration()->Node() != nullptr && + var->Declaration()->Node()->IsETSParameterExpression() && + var->Declaration()->Node()->AsETSParameterExpression()->HasAnnotations()) { + func.params.back().GetOrCreateMetadata()->SetAnnotations(emitter->GenCustomAnnotations( + var->Declaration()->Node()->AsETSParameterExpression()->Annotations(), var->Name().Mutf8())); + } + } + + if (scriptFunc->IsConstructor() || scriptFunc->IsStaticBlock()) { + func.returnType = pandasm::Type(Signatures::PRIMITIVE_VOID, 0); + } else { + func.returnType = PandasmTypeWithRank(emitter, scriptFunc->Signature()->ReturnType()); } + func.metadata->SetAccessFlags(ComputeAccessFlags(scriptFunc)); + if (scriptFunc->IsConstructor()) { func.metadata->SetAttribute(Signatures::CONSTRUCTOR); } + if (external) { + func.metadata->SetAttribute(Signatures::EXTERNAL); + } else { + if (scriptFunc->HasAnnotations()) { + auto annotations = emitter->GenCustomAnnotations(scriptFunc->Annotations(), func.name); + func.metadata->SetAnnotations(std::move(annotations)); + } + if (scriptFunc->IsAsyncFunc()) { + // callee does not tolerate constness + func.metadata->AddAnnotations({ + emitter->GenAnnotationAsync(const_cast(scriptFunc)), + }); + } + } return func; } +ETSEmitter::ETSEmitter(const public_lib::Context *context) + : Emitter(context), symbols_(std::make_unique()) +{ +} + +ETSEmitter::~ETSEmitter() { + // for PImpl +}; + +std::string ETSEmitter::AddDependence(std::string str) +{ + return symbols_->AddDependence(str); +} + pandasm::Function *ETSFunctionEmitter::GenFunctionSignature() { auto *scriptFunc = Cg()->RootNode()->AsScriptFunction(); + if (scriptFunc->IsExternal() || scriptFunc->Signature()->Owner()->GetDeclNode()->IsDeclare()) { + return nullptr; + } auto *emitter = static_cast(Cg()->Context()->emitter); - auto func = GenScriptFunction(scriptFunc, emitter); - - if (Cg()->RootNode()->AsScriptFunction()->IsExternal()) { + auto func = GenScriptFunction(scriptFunc, emitter, false); + if (scriptFunc->IsExternal()) { // why do we emit an external method? func.metadata->SetAttribute(Signatures::EXTERNAL); } @@ -204,26 +331,15 @@ void ETSFunctionEmitter::GenSourceFileDebugInfo(pandasm::Function *func) } } -void ETSFunctionEmitter::GenFunctionAnnotations([[maybe_unused]] pandasm::Function *func) {} - -static pandasm::Function GenExternalFunction(checker::Signature *signature, bool isCtor) +void ETSFunctionEmitter::GenFunctionAnnotations([[maybe_unused]] pandasm::Function *func) { - auto func = pandasm::Function(signature->InternalName().Mutf8(), EXTENSION); - - for (auto param : signature->Params()) { - func.params.emplace_back(PandasmTypeWithRank(param->TsType()), EXTENSION); + auto emitter = static_cast(Cg())->Emitter(); + for (const auto *catchBlock : Cg()->CatchList()) { + emitter->AddDependence(catchBlock->Exception()); } - func.returnType = PandasmTypeWithRank(signature->ReturnType()); - - if (isCtor) { - func.metadata->SetAttribute(Signatures::CONSTRUCTOR); - } - func.metadata->SetAttribute(Signatures::EXTERNAL); - - return func; } -void FilterForSimultaneous(varbinder::ETSBinder *varbinder) +static void FilterForSimultaneous(varbinder::ETSBinder *varbinder) { ArenaSet &classDefinitions = varbinder->GetGlobalRecordTable()->ClassDefinitions(); for (auto it = classDefinitions.begin(); it != classDefinitions.end(); ++it) { @@ -232,6 +348,7 @@ void FilterForSimultaneous(varbinder::ETSBinder *varbinder) break; } } + // obsolete if record itself will not be emitted std::vector filterFunctions = { Signatures::UNUSED_ETSGLOBAL_CTOR, Signatures::UNUSED_ETSGLOBAL_INIT, Signatures::UNUSED_ETSGLOBAL_MAIN}; auto &functions = varbinder->Functions(); @@ -244,23 +361,27 @@ void FilterForSimultaneous(varbinder::ETSBinder *varbinder) functions.end()); } -void ETSEmitter::GenRecords(varbinder::RecordTable *globalRecordTable) +void ETSEmitter::GenFunction(ir::ScriptFunction const *scriptFunc, bool external) { - auto *varbinder = static_cast(Context()->parserProgram->VarBinder()); - auto baseName = varbinder->GetRecordTable()->RecordName().Mutf8(); - for (auto *annoDecl : globalRecordTable->AnnotationDeclarations()) { - std::string newBaseName = util::NameMangler::GetInstance()->CreateMangledNameForAnnotation( - baseName, annoDecl->GetBaseName()->Name().Mutf8()); - GenCustomAnnotationRecord(annoDecl, newBaseName, annoDecl->IsDeclare()); + if (!external && scriptFunc->Body() != nullptr) { + return; // was already produced by codegen } - - for (auto *classDecl : globalRecordTable->ClassDefinitions()) { - GenClassRecord(classDecl, classDecl->IsDeclare()); + auto name = ToAssemblerSignature(scriptFunc); + if (symbols_->IsNotRequired(name, external)) { + return; } - for (auto *interfaceDecl : globalRecordTable->InterfaceDeclarations()) { - GenInterfaceRecord(interfaceDecl, interfaceDecl->IsDeclare()); + auto func = GenScriptFunction(scriptFunc, this, external || scriptFunc->IsDeclare()); // #28197 + if (scriptFunc->Signature()->HasSignatureFlag(checker::SignatureFlags::STATIC) && + Program()->functionStaticTable.find(name) != Program()->functionStaticTable.cend()) { + return; + } + if (!scriptFunc->Signature()->HasSignatureFlag(checker::SignatureFlags::STATIC) && + Program()->functionInstanceTable.find(name) != Program()->functionInstanceTable.cend()) { + return; } + + Program()->AddToFunctionTable(std::move(func)); } void ETSEmitter::GenAnnotation() @@ -271,95 +392,78 @@ void ETSEmitter::GenAnnotation() if (Context()->config->options->GetCompilationMode() == CompilationMode::GEN_ABC_FOR_EXTERNAL_SOURCE) { FilterForSimultaneous(varbinder); } + ES2PANDA_ASSERT(varbinder->GetRecordTable() == varbinder->GetGlobalRecordTable()); - auto *globalRecordTable = varbinder->GetGlobalRecordTable(); - GenRecords(globalRecordTable); - - for (auto *signature : globalRecordTable->Signatures()) { - auto *scriptFunc = signature->Node()->AsScriptFunction(); - auto func = GenScriptFunction(scriptFunc, this); - if (scriptFunc->IsDeclare()) { - func.metadata->SetAttribute(Signatures::EXTERNAL); - } - if (scriptFunc->IsAsyncFunc()) { - std::vector annotations; - annotations.push_back(GenAnnotationAsync(scriptFunc)); - func.metadata->AddAnnotations(annotations); + auto const traverseRecords = [this, varbinder](bool traverseExternals) { + EmitRecordTable(varbinder->GetGlobalRecordTable(), false, traverseExternals); + auto *saveProgram = varbinder->Program(); + for (auto [extProg, recordTable] : varbinder->GetExternalRecordTable()) { + if (recordTable == varbinder->GetGlobalRecordTable()) { + continue; + } + bool programIsExternal = !(varbinder->IsGenStdLib() || recordTable->Program()->IsGenAbcForExternal()); + varbinder->SetProgram(extProg); + EmitRecordTable(recordTable, programIsExternal, traverseExternals); } - Program()->AddToFunctionTable(std::move(func)); - } - - auto *saveProgram = varbinder->Program(); - for (auto [extProg, recordTable] : varbinder->GetExternalRecordTable()) { - if (recordTable == varbinder->GetRecordTable()) { - continue; + varbinder->SetProgram(saveProgram); + if (traverseExternals) { + const auto *checker = static_cast(Context()->GetChecker()); + for (auto [arrType, _] : checker->GlobalArrayTypes()) { + GenGlobalArrayRecord(arrType); + } + for (auto unionType : checker->UnionAssemblerTypes()) { + GenGlobalUnionRecord(unionType); + } } - varbinder->SetProgram(extProg); - GenExternalRecord(recordTable, extProg); - } - varbinder->SetProgram(saveProgram); - - const auto *checker = static_cast(Context()->GetChecker()); + }; - for (auto [arrType, signature] : checker->GlobalArrayTypes()) { - GenGlobalArrayRecord(arrType, signature); - } - for (auto unionType : checker->UnionAssemblerTypes()) { - auto unionRecord = pandasm::Record(unionType.Mutf8(), Program()->lang); - unionRecord.metadata->SetAttribute(Signatures::EXTERNAL); - Program()->recordTable.emplace(unionRecord.name, std::move(unionRecord)); - } + // compile non-external dependencies + traverseRecords(false); + symbols_->ProcessToEmission(); + // compile external dependencies + traverseRecords(true); // initial pass, which contributes to the difference + symbols_->ProceedToMissingRecord(); // compute the difference + traverseRecords(true); // re-run the pass + symbols_.reset(); } -static bool IsFromSelfHeadFile(const std::string &name, const parser::Program *curProg, const parser::Program *extProg) +void ETSEmitter::EmitRecordTable(varbinder::RecordTable *table, bool programIsExternal, bool traverseExternals) { - const auto *curBinder = static_cast(curProg->VarBinder()); - return extProg->FileName() == curProg->FileName() && - std::any_of(curBinder->Functions().begin(), curBinder->Functions().end(), - [&](auto function) { return function->InternalName().Is(name); }); -} + // #28197: We should just bailout if programIsExternal is not equal to traverseExternals, but there are + // some sources which have declare* entities inside non-declare programs + // Also, IsDeclare() for entity implies the program is external! + // after it is fixed, the parameter traverseExternals to be removed + if (!traverseExternals && programIsExternal) { // #28197 + return; + } -void ETSEmitter::GenExternalRecord(varbinder::RecordTable *recordTable, const parser::Program *extProg) -{ - bool isExternalFromCompile = - !recordTable->Program()->VarBinder()->IsGenStdLib() && !recordTable->Program()->IsGenAbcForExternal(); const auto *varbinder = static_cast(Context()->parserProgram->VarBinder()); + auto baseName = varbinder->GetRecordTable()->RecordName().Mutf8(); - for (auto *annoDecl : recordTable->AnnotationDeclarations()) { + for (auto *annoDecl : table->AnnotationDeclarations()) { + auto external = programIsExternal || annoDecl->IsDeclare(); + if (external != traverseExternals) { // #28197 + continue; + } std::string newBaseName = util::NameMangler::GetInstance()->CreateMangledNameForAnnotation( baseName, annoDecl->GetBaseName()->Name().Mutf8()); - GenCustomAnnotationRecord(annoDecl, newBaseName, isExternalFromCompile || annoDecl->IsDeclare()); - } - - for (auto *classDecl : recordTable->ClassDefinitions()) { - GenClassRecord(classDecl, isExternalFromCompile || classDecl->IsDeclare()); - } - - for (auto *interfaceDecl : recordTable->InterfaceDeclarations()) { - GenInterfaceRecord(interfaceDecl, isExternalFromCompile || interfaceDecl->IsDeclare()); + GenCustomAnnotationRecord(annoDecl, newBaseName, external); } - for (auto *signature : recordTable->Signatures()) { - auto scriptFunc = signature->Node()->AsScriptFunction(); - auto func = GenScriptFunction(scriptFunc, this); - - if (isExternalFromCompile || scriptFunc->IsDeclare()) { - func.metadata->SetAttribute(Signatures::EXTERNAL); - } - - if (extProg->IsGenAbcForExternal() && scriptFunc->IsAsyncFunc()) { - std::vector annotations; - annotations.push_back(GenAnnotationAsync(scriptFunc)); - func.metadata->AddAnnotations(annotations); - } - - if (func.metadata->IsForeign() && IsFromSelfHeadFile(func.name, Context()->parserProgram, extProg)) { + for (auto *classDecl : table->ClassDefinitions()) { + auto external = programIsExternal || classDecl->IsDeclare(); + if (external != traverseExternals) { // #28197 continue; } + GenClassRecord(classDecl, external); + } - if (Program()->functionStaticTable.find(func.name) == Program()->functionStaticTable.cend()) { - Program()->AddToFunctionTable(std::move(func)); + for (auto *interfaceDecl : table->InterfaceDeclarations()) { + auto external = programIsExternal || interfaceDecl->IsDeclare(); + if (external != traverseExternals) { // #28197 + continue; } + GenInterfaceRecord(interfaceDecl, external); } } @@ -441,36 +545,23 @@ void ETSEmitter::EmitDefaultFieldValue(pandasm::Field &classField, const ir::Exp classField.metadata->SetValue(CreateScalarValue(init->AsLiteral(), typeKind)); } -void ETSEmitter::GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external) +void ETSEmitter::GenClassField(const ir::ClassProperty *prop, pandasm::Record &classRecord, bool external) { - auto *scriptFunc = methodDef->Function(); - auto func = GenScriptFunction(scriptFunc, this); - - if (external) { - func.metadata->SetAttribute(Signatures::EXTERNAL); - } - - if (scriptFunc->Body() != nullptr) { + if (symbols_->IsNotRequired(classRecord.name + '.' + prop->Id()->Name().Mutf8(), external)) { return; } - func.metadata->SetAccessFlags(func.metadata->GetAccessFlags() | ACC_ABSTRACT); - Program()->AddToFunctionTable(std::move(func)); -} - -void ETSEmitter::GenClassField(const ir::ClassProperty *prop, pandasm::Record &classRecord, bool external) -{ auto field = pandasm::Field(Program()->lang); ES2PANDA_ASSERT(prop->Id() != nullptr); field.name = prop->Id()->Name().Mutf8(); - field.type = PandasmTypeWithRank(prop->TsType()); + field.type = PandasmTypeWithRank(this, prop->TsType()); field.metadata->SetAccessFlags(TranslateModifierFlags(prop->Modifiers())); if (!external && prop->HasAnnotations()) { field.metadata->SetAnnotations(GenCustomAnnotations(prop->Annotations(), field.name)); } - if (external || prop->IsDeclare()) { + if (external || prop->IsDeclare()) { // #28197 field.metadata->SetAttribute(Signatures::EXTERNAL); } else if (prop->TsType()->IsETSPrimitiveType() || prop->TsType()->IsETSStringType()) { EmitDefaultFieldValue(field, prop->Value()); @@ -479,91 +570,110 @@ void ETSEmitter::GenClassField(const ir::ClassProperty *prop, pandasm::Record &c classRecord.fieldList.emplace_back(std::move(field)); } -void ETSEmitter::GenClassInheritedFields(const checker::ETSObjectType *baseType, pandasm::Record &classRecord) +void ETSEmitter::GenGlobalArrayRecord(const checker::ETSArrayType *arrayType) { - std::vector foreignProps = baseType->ForeignProperties(); + // escompat.taskpool.ThreadInfo[]. : escompat.taskpool.ThreadInfo[]; i32; void; + auto name = static_cast(arrayType)->ToAssemblerTypeWithRank(); + if (symbols_->IsNotRequired(name)) { + return; + } + if (Program()->recordTable.find(name) != Program()->recordTable.end()) { + return; + } - for (const auto *foreignProp : foreignProps) { - auto *declNode = foreignProp->Declaration()->Node(); - if (!declNode->IsClassProperty()) { - continue; - } + auto arrayRecord = pandasm::Record(name, Program()->lang); + arrayRecord.metadata->SetAttribute(Signatures::EXTERNAL); + Program()->AddToRecordTable(std::move(arrayRecord)); + Program()->arrayTypes.emplace(PandasmTypeWithRank(this, arrayType)); + + std::vector params; + auto singatureName = name + ".:" + name + ";"; + params.emplace_back(pandasm::Type(name, 0), EXTENSION); + for (size_t i = 0; i < arrayType->Rank(); ++i) { + singatureName += "i32;"; + params.emplace_back(pandasm::Type("i32", 0), EXTENSION); + } + singatureName += "void;"; + + auto ctor = pandasm::Function(singatureName, EXTENSION); + ctor.params = std::move(params); + ctor.returnType = pandasm::Type("void", 0); + ctor.metadata->SetAttribute(Signatures::CONSTRUCTOR); + ctor.metadata->SetAttribute(Signatures::EXTERNAL); + Program()->AddToFunctionTable(std::move(ctor)); +} - GenClassField(declNode->AsClassProperty(), classRecord, true); +void ETSEmitter::GenGlobalUnionRecord(util::StringView assemblerType) +{ + std::string name = assemblerType.Mutf8(); + if (symbols_->IsNotRequired(name)) { + return; + } + if (Program()->recordTable.find(name) != Program()->recordTable.end()) { + return; } + auto unionRecord = pandasm::Record(name, Program()->lang); + unionRecord.metadata->SetAttribute(Signatures::EXTERNAL); + Program()->AddToRecordTable(std::move(unionRecord)); } -void ETSEmitter::GenGlobalArrayRecord(const checker::ETSArrayType *arrayType, checker::Signature *signature) +void ETSEmitter::GenMethodDefinition(ir::MethodDefinition const *method, bool external) { - std::stringstream ss; - arrayType->ToAssemblerTypeWithRank(ss); - - auto arrayRecord = pandasm::Record(ss.str(), Program()->lang); + // TODO(vpukhov): method should not be external if the class is not external! + // it appears in some positive tests, but such method can not be even compiled - auto func = GenExternalFunction(signature, true); - func.params.emplace(func.params.begin(), pandasm::Type(ss.str(), 0), EXTENSION); - - Program()->AddToFunctionTable(std::move(func)); - - arrayRecord.metadata->SetAttribute(Signatures::EXTERNAL); - Program()->recordTable.emplace(arrayRecord.name, std::move(arrayRecord)); - Program()->arrayTypes.emplace(PandasmTypeWithRank(arrayType)); + GenFunction(method->Function(), external); + for (auto *overload : method->Overloads()) { + GenFunction(overload->Function(), external); + } } void ETSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external) { - auto *baseType = interfaceDecl->TsType()->IsGradualType() - ? interfaceDecl->TsType()->AsGradualType()->GetBaseType()->AsETSObjectType() - : interfaceDecl->TsType()->AsETSObjectType(); - auto interfaceRecord = pandasm::Record(interfaceDecl->InternalName().Mutf8(), Program()->lang); - - uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE; - if (interfaceDecl->IsStatic()) { - accessFlags |= ACC_STATIC; + if (symbols_->IsNotRequired(ToAssemblerType(interfaceDecl), external)) { + return; } + auto interfaceRecord = pandasm::Record(ToAssemblerType(interfaceDecl), Program()->lang); - if (interfaceDecl->HasAnnotations()) { - interfaceRecord.metadata->SetAnnotations( - GenCustomAnnotations(interfaceDecl->Annotations(), interfaceRecord.name)); - } - interfaceRecord.metadata->SetAccessFlags(accessFlags); + interfaceRecord.metadata->SetAccessFlags(ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE); interfaceRecord.sourceFile = std::string {Context()->parserProgram->VarBinder()->Program()->RelativeFilePath()}; - interfaceRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT); - - GenClassInheritedFields(baseType, interfaceRecord); for (const auto *prop : interfaceDecl->Body()->Body()) { - if (prop->IsClassProperty()) { - GenClassField(prop->AsClassProperty(), interfaceRecord, external); - } else if (prop->IsMethodDefinition()) { - GenInterfaceMethodDefinition(prop->AsMethodDefinition(), external); - for (auto *overload : prop->AsMethodDefinition()->Overloads()) { - GenInterfaceMethodDefinition(overload, external); - } + if (prop->IsMethodDefinition()) { + GenMethodDefinition(prop->AsMethodDefinition(), external); } } - if (std::any_of(interfaceDecl->Body()->Body().begin(), interfaceDecl->Body()->Body().end(), - [](const ir::AstNode *node) { return node->IsOverloadDeclaration(); })) { - std::vector annotations {}; - annotations.emplace_back(GenAnnotationFunctionOverload(interfaceDecl->Body()->Body())); - interfaceRecord.metadata->AddAnnotations(annotations); - } - if (external) { interfaceRecord.metadata->SetAttribute(Signatures::EXTERNAL); - Program()->recordTable.emplace(interfaceRecord.name, std::move(interfaceRecord)); + Program()->AddToRecordTable(std::move(interfaceRecord)); return; } + interfaceRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT); + + auto *baseType = interfaceDecl->TsType()->IsGradualType() + ? interfaceDecl->TsType()->AsGradualType()->GetBaseType()->AsETSObjectType() + : interfaceDecl->TsType()->AsETSObjectType(); for (auto *it : baseType->Interfaces()) { auto *declNode = it->GetDeclNode(); ES2PANDA_ASSERT(declNode->IsTSInterfaceDeclaration()); - std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8(); - interfaceRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name); + interfaceRecord.metadata->SetAttributeValue( + Signatures::IMPLEMENTS_ATTRIBUTE, AddDependence(ToAssemblerType(declNode->AsTSInterfaceDeclaration()))); } - Program()->recordTable.emplace(interfaceRecord.name, std::move(interfaceRecord)); + if (interfaceDecl->HasAnnotations()) { + interfaceRecord.metadata->SetAnnotations( + GenCustomAnnotations(interfaceDecl->Annotations(), interfaceRecord.name)); + } + if (std::any_of(interfaceDecl->Body()->Body().begin(), interfaceDecl->Body()->Body().end(), + [](const ir::AstNode *node) { return node->IsOverloadDeclaration(); })) { + std::vector annotations {}; + annotations.emplace_back(GenAnnotationFunctionOverload(interfaceDecl->Body()->Body())); + interfaceRecord.metadata->AddAnnotations(annotations); + } + + Program()->AddToRecordTable(std::move(interfaceRecord)); } std::vector ETSEmitter::GenAnnotations(const ir::ClassDefinition *classDef) @@ -615,47 +725,40 @@ static uint32_t GetAccessFlags(const ir::ClassDefinition *classDef) void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool external) { - auto classRecord = pandasm::Record(classDef->InternalName().Mutf8(), Program()->lang); + if (symbols_->IsNotRequired(ToAssemblerType(classDef), external)) { + return; + } + auto classRecord = pandasm::Record(ToAssemblerType(classDef), Program()->lang); uint32_t accessFlags = GetAccessFlags(classDef); classRecord.metadata->SetAccessFlags(accessFlags); classRecord.sourceFile = std::string {Context()->parserProgram->VarBinder()->Program()->RelativeFilePath()}; - auto *baseType = classDef->TsType()->IsGradualType() - ? classDef->TsType()->AsGradualType()->GetBaseType()->AsETSObjectType() - : classDef->TsType()->AsETSObjectType(); - GenClassInheritedFields(baseType, classRecord); + for (const auto *prop : classDef->Body()) { - if (!prop->IsClassProperty()) { - continue; + if (prop->IsClassProperty()) { + GenClassField(prop->AsClassProperty(), classRecord, external); + } else if (prop->IsMethodDefinition()) { + GenMethodDefinition(prop->AsMethodDefinition(), external); } - - GenClassField(prop->AsClassProperty(), classRecord, external); } if (external) { classRecord.metadata->SetAttribute(Signatures::EXTERNAL); - Program()->recordTable.emplace(classRecord.name, std::move(classRecord)); + Program()->AddToRecordTable(std::move(classRecord)); return; } + auto *baseType = classDef->TsType()->IsGradualType() + ? classDef->TsType()->AsGradualType()->GetBaseType()->AsETSObjectType() + : classDef->TsType()->AsETSObjectType(); if (baseType->SuperType() != nullptr) { classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, - baseType->SuperType()->AssemblerName().Mutf8()); - } else { - // NOTE: rtakacs. Replace the whole if block (below) with assert when lambda objects have super class. - if (baseType->AssemblerName().Mutf8() != Signatures::BUILTIN_OBJECT) { - classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT); - } + AddDependence(ToAssemblerType(baseType->SuperType()->GetDeclNode()))); } for (auto *it : baseType->Interfaces()) { - auto *declNode = it->GetDeclNode(); - // NOTE: itrubachev. replace it with ES2PANDA_ASSERT(decl_node->IsTSInterfaceDeclaration()) - // after adding proper creation of lambda object in ETSFunctionType::AssignmentSource - if (!declNode->IsTSInterfaceDeclaration()) { - continue; - } - std::string name = declNode->AsTSInterfaceDeclaration()->InternalName().Mutf8(); - classRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, name); + classRecord.metadata->SetAttributeValue( + Signatures::IMPLEMENTS_ATTRIBUTE, + AddDependence(ToAssemblerType(it->GetDeclNode()->AsTSInterfaceDeclaration()))); } if (classDef->HasAnnotations()) { @@ -668,10 +771,10 @@ void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool extern } if (!annotations.empty() && !classDef->IsLazyImportObjectClass()) { - classRecord.metadata->AddAnnotations(annotations); + classRecord.metadata->AddAnnotations(std::move(annotations)); } - Program()->recordTable.emplace(classRecord.name, std::move(classRecord)); + Program()->AddToRecordTable(std::move(classRecord)); } void ETSEmitter::ProcessArrayExpression( @@ -793,8 +896,9 @@ LiteralArrayVector ETSEmitter::CreateLiteralArray(std::string &baseName, const i ProcessArrayElement(elem, literals, baseName, result); } + static uint32_t litArrayValueCount = 0; std::string litArrayName = - util::NameMangler::GetInstance()->AppendToAnnotationName(baseName, std::to_string(g_litArrayValueCount++)); + util::NameMangler::GetInstance()->AppendToAnnotationName(baseName, std::to_string(litArrayValueCount++)); result.emplace_back(litArrayName, literals); return result; } @@ -808,19 +912,18 @@ void ETSEmitter::CreateLiteralArrayProp(const ir::ClassProperty *prop, std::stri ++rank; elemType = checker->GetElementTypeOfArray(elemType); } - std::stringstream ss; - elemType->ToAssemblerType(ss); - field.type = pandasm::Type(ss.str(), rank); + field.type = pandasm::Type(AddDependence(elemType->ToAssemblerType()), rank); auto value = prop->Value(); if (value != nullptr) { std::string newBaseName = util::NameMangler::GetInstance()->AppendToAnnotationName(baseName, field.name); auto litArray = CreateLiteralArray(newBaseName, value); - for (const auto &item : litArray) { - Program()->literalarrayTable.emplace(item.first, item.second); + auto const metaValue = litArray.back().first; + + for (auto &item : litArray) { + Program()->AddToLiteralArrayTable(std::move(item.second), item.first); } - field.metadata->SetValue( - pandasm::ScalarValue::Create(std::string_view {litArray.back().first})); + field.metadata->SetValue(pandasm::ScalarValue::Create(metaValue)); } } @@ -831,7 +934,7 @@ void ETSEmitter::GenCustomAnnotationProp(const ir::ClassProperty *prop, std::str auto *type = prop->TsType(); ES2PANDA_ASSERT(prop->Id() != nullptr); field.name = prop->Id()->Name().Mutf8(); - field.type = PandasmTypeWithRank(type); + field.type = PandasmTypeWithRank(this, type); field.metadata->SetAccessFlags(TranslateModifierFlags(prop->Modifiers())); if (external) { @@ -851,10 +954,10 @@ void ETSEmitter::GenCustomAnnotationProp(const ir::ClassProperty *prop, std::str void ETSEmitter::GenCustomAnnotationRecord(const ir::AnnotationDeclaration *annoDecl, std::string &baseName, bool external) { - auto annoRecord = pandasm::Record(annoDecl->InternalName().Mutf8(), Program()->lang); - if (Program()->recordTable.find(annoRecord.name) != Program()->recordTable.end()) { + if (symbols_->IsNotRequired(ToAssemblerType(annoDecl), external)) { return; } + auto annoRecord = pandasm::Record(ToAssemblerType(annoDecl), Program()->lang); if (external) { annoRecord.metadata->SetAttribute(Signatures::EXTERNAL); @@ -867,7 +970,7 @@ void ETSEmitter::GenCustomAnnotationRecord(const ir::AnnotationDeclaration *anno GenCustomAnnotationProp(it->AsClassProperty(), baseName, annoRecord, external); } - Program()->recordTable.emplace(annoRecord.name, std::move(annoRecord)); + Program()->AddToRecordTable(std::move(annoRecord)); } pandasm::AnnotationElement ETSEmitter::ProcessArrayType(const ir::ClassProperty *prop, std::string &baseName, @@ -877,14 +980,15 @@ pandasm::AnnotationElement ETSEmitter::ProcessArrayType(const ir::ClassProperty auto propName = prop->Id()->Name().Mutf8(); std::string newBaseName = util::NameMangler::GetInstance()->AppendToAnnotationName(baseName, propName); auto litArrays = CreateLiteralArray(newBaseName, init); + auto const value = litArrays.back().first; - for (const auto &item : litArrays) { - Program()->literalarrayTable.emplace(item.first, item.second); + for (auto &item : litArrays) { + Program()->AddToLiteralArrayTable(std::move(item.second), item.first); } return pandasm::AnnotationElement { - propName, std::make_unique(pandasm::ScalarValue::Create( - std::string_view {litArrays.back().first}))}; + propName, + std::make_unique(pandasm::ScalarValue::Create(value))}; } static pandasm::AnnotationElement ProcessETSEnumType(std::string &baseName, const ir::Expression *init, @@ -927,13 +1031,14 @@ pandasm::AnnotationElement ETSEmitter::GenCustomAnnotationElement(const ir::Clas pandasm::AnnotationData ETSEmitter::GenCustomAnnotation(ir::AnnotationUsage *anno, std::string &baseName) { auto *annoDecl = anno->GetBaseName()->Variable()->Declaration()->Node()->AsAnnotationDeclaration(); - pandasm::AnnotationData annotation(annoDecl->InternalName().Mutf8()); + pandasm::AnnotationData annotation(AddDependence(ToAssemblerType(annoDecl))); if (annoDecl->IsImportDeclaration()) { - auto annoRecord = pandasm::Record(annoDecl->InternalName().Mutf8(), Program()->lang); + // TODO(vpukhov): duplication + auto annoRecord = pandasm::Record(ToAssemblerType(annoDecl), Program()->lang); annoRecord.metadata->SetAttribute(Signatures::EXTERNAL); uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_ANNOTATION; annoRecord.metadata->SetAccessFlags(accessFlags); - Program()->recordTable.emplace(annoRecord.name, std::move(annoRecord)); + Program()->AddToRecordTable(std::move(annoRecord)); } for (auto *prop : anno->Properties()) { @@ -962,8 +1067,11 @@ pandasm::AnnotationData ETSEmitter::GenAnnotationModule(const ir::ClassDefinitio std::vector exportedClasses {}; for (auto cls : classDef->ExportedClasses()) { + if (cls->IsDeclare()) { // #28197 + continue; // AST inconsistency! + } exportedClasses.emplace_back(pandasm::ScalarValue::Create( - pandasm::Type::FromName(cls->Definition()->InternalName().Utf8(), true))); + pandasm::Type::FromName(AddDependence(ToAssemblerType(cls->Definition())), true))); } GenAnnotationRecord(Signatures::ETS_ANNOTATION_MODULE); @@ -1001,43 +1109,6 @@ pandasm::AnnotationData ETSEmitter::GenAnnotationFunctionOverload(const ArenaVec return overloadAnno; } -pandasm::AnnotationData ETSEmitter::GenAnnotationSignature(const ir::ClassDefinition *classDef) -{ - std::vector parts {}; - const auto &typeParams = classDef->TypeParams()->Params(); - - auto const addStringValue = [&parts](std::string_view str) { - parts.emplace_back(pandasm::ScalarValue::Create(str)); - }; - - if (!typeParams.empty()) { - addStringValue(Signatures::GENERIC_BEGIN); - - for (const auto *param : typeParams) { - addStringValue(Signatures::MANGLE_BEGIN); - std::stringstream ss; - param->Constraint()->TsType()->ToAssemblerTypeWithRank(ss); - auto asmName = util::StringView(ss.str()); - addStringValue(checker::ETSObjectType::NameToDescriptor(asmName)); - } - addStringValue(Signatures::GENERIC_END); - } - - if (auto super = classDef->TsType()->AsETSObjectType()->SuperType(); super != nullptr) { - addStringValue(checker::ETSObjectType::NameToDescriptor(util::StringView(super->AssemblerName().Mutf8()))); - } else { - addStringValue(checker::ETSObjectType::NameToDescriptor(Signatures::BUILTIN_OBJECT)); - } - - GenAnnotationRecord(Signatures::ETS_ANNOTATION_SIGNATURE); - pandasm::AnnotationData signature(Signatures::ETS_ANNOTATION_SIGNATURE); - pandasm::AnnotationElement value( - Signatures::ANNOTATION_KEY_VALUE, - std::make_unique(pandasm::Value::Type::STRING, std::move(parts))); - signature.AddElement(std::move(value)); - return signature; -} - pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef) { GenAnnotationRecord(Signatures::ETS_ANNOTATION_ENCLOSING_METHOD); @@ -1152,8 +1223,8 @@ pandasm::AnnotationData ETSEmitter::GenAnnotationAsync(ir::ScriptFunction *scrip pandasm::AnnotationData ann(Signatures::ETS_COROUTINE_ASYNC); pandasm::AnnotationElement value( Signatures::ANNOTATION_KEY_VALUE, - std::make_unique(pandasm::ScalarValue::Create( - impl->Function()->Scope()->InternalName().Mutf8()))); + std::make_unique( + pandasm::ScalarValue::Create(ToAssemblerSignature(impl->Function())))); ann.AddElement(std::move(value)); return ann; } @@ -1174,7 +1245,7 @@ void ETSEmitter::GenAnnotationRecord(std::string_view recordNameView, bool isRun } else if (!isRuntime && isType) { record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::TYPE_ANNOTATION); } - Program()->recordTable.emplace(record.name, std::move(record)); + Program()->AddToRecordTable(std::move(record)); } } } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/core/ETSemitter.h b/ets2panda/compiler/core/ETSemitter.h index 3a5a40631e24fb9544b5e4ad2f7f971e58683bfe..37d41540e21bbdff27afa320af564b0978f0c85a 100644 --- a/ets2panda/compiler/core/ETSemitter.h +++ b/ets2panda/compiler/core/ETSemitter.h @@ -16,6 +16,12 @@ #ifndef ES2PANDA_COMPILER_CORE_ETS_EMITTER_H #define ES2PANDA_COMPILER_CORE_ETS_EMITTER_H +#include +#include +#include +#include +#include + #include "annotation.h" #include "assembly-literals.h" #include "emitter.h" @@ -58,11 +64,6 @@ public: NO_MOVE_SEMANTIC(ETSFunctionEmitter); protected: - const ETSGen *Etsg() const - { - return reinterpret_cast(Cg()); - } - pandasm::Function *GenFunctionSignature() override; void GenFunctionAnnotations(pandasm::Function *func) override; @@ -71,21 +72,29 @@ protected: void GenSourceFileDebugInfo(pandasm::Function *func) override; }; +namespace detail { +class EmitterDependencies; +} + class ETSEmitter : public Emitter { public: - explicit ETSEmitter(const public_lib::Context *context) : Emitter(context) {} - ~ETSEmitter() override = default; + explicit ETSEmitter(const public_lib::Context *context); + ~ETSEmitter() override; NO_COPY_SEMANTIC(ETSEmitter); NO_MOVE_SEMANTIC(ETSEmitter); void GenAnnotation() override; + + // Handle a broken dependence between annotation handling and shared emitter code std::vector GenCustomAnnotations( const ArenaVector &annotationUsages, const std::string &baseName); + pandasm::AnnotationData GenAnnotationAsync(ir::ScriptFunction *scriptFunc); + std::string AddDependence(std::string str); private: - void GenRecords(varbinder::RecordTable *globalRecordTable); - void GenExternalRecord(varbinder::RecordTable *recordTable, const parser::Program *extProg); - void GenGlobalArrayRecord(const checker::ETSArrayType *arrayType, checker::Signature *signature); + void EmitRecordTable(varbinder::RecordTable *recordTable, bool externalize, bool isTraverseExternalsPhase); + void GenGlobalArrayRecord(const checker::ETSArrayType *arrayType); + void GenGlobalUnionRecord(util::StringView assemblerType); std::vector GenAnnotations(const ir::ClassDefinition *classDef); void GenClassRecord(const ir::ClassDefinition *classDef, bool external); pandasm::AnnotationElement ProcessArrayType(const ir::ClassProperty *prop, std::string &baseName, @@ -105,19 +114,20 @@ private: void EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init); void GenClassField(const ir::ClassProperty *prop, pandasm::Record &classRecord, bool external); - void GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external); + void GenMethodDefinition(ir::MethodDefinition const *method, bool external); + void GenFunction(ir::ScriptFunction const *scriptFunc, bool external); void GenClassInheritedFields(const checker::ETSObjectType *baseType, pandasm::Record &classRecord); - pandasm::AnnotationData GenAnnotationSignature(const ir::ClassDefinition *classDef); pandasm::AnnotationData GenAnnotationModule(const ir::ClassDefinition *classDef); pandasm::AnnotationData GenAnnotationFunctionOverload(const ArenaVector &body); pandasm::AnnotationData GenAnnotationEnclosingClass(std::string_view className); pandasm::AnnotationData GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef); pandasm::AnnotationData GenAnnotationFunctionalReference(const ir::ClassDefinition *classDef); pandasm::AnnotationData GenAnnotationInnerClass(const ir::ClassDefinition *classDef, const ir::AstNode *parent); - pandasm::AnnotationData GenAnnotationAsync(ir::ScriptFunction *scriptFunc); ir::MethodDefinition *FindAsyncImpl(ir::ScriptFunction *asyncFunc); void ProcessArrayExpression(std::string &baseName, LiteralArrayVector &result, std::vector &literals, const ir::Expression *elem); + + std::unique_ptr symbols_; }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/core/ETSfunction.cpp b/ets2panda/compiler/core/ETSfunction.cpp index 2daa3e0167a08288caac9c806532fc80aa377684..af91c7d094e4199a180f9de1fe3eb7c738dc8815 100644 --- a/ets2panda/compiler/core/ETSfunction.cpp +++ b/ets2panda/compiler/core/ETSfunction.cpp @@ -146,10 +146,15 @@ void ETSFunction::CompileAsConstructor(ETSGen *etsg, const ir::ScriptFunction *s void ETSFunction::CompileFunction(ETSGen *etsg) { - if (const auto *decl = etsg->RootNode()->AsScriptFunction(); !decl->IsDeclare() && !decl->IsExternal()) { - if (auto *const body = decl->Body(); body != nullptr && body->IsBlockStatement()) { - CompileSourceBlock(etsg, body->AsBlockStatement()); - } + const auto *decl = etsg->RootNode()->AsScriptFunction(); + if (decl->IsDeclare() || decl->IsExternal()) { + return; // such methods should've been filtered in advance + } + if (decl->Signature()->Owner()->GetDeclNode()->IsDeclare()) { + return; // AST inconsistency! + } + if (auto *const body = decl->Body(); body != nullptr && body->IsBlockStatement()) { + CompileSourceBlock(etsg, body->AsBlockStatement()); } } diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 37b272b0ce47d00019c588078a02726084bdaa0e..2e406c4d1e8ac6e7daa2050060c187024a79c7c4 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -63,7 +63,7 @@ void CompilerImpl::HandleContextLiterals(public_lib::Context *context) emitter->LiteralBufferIndex() += context->contextLiterals.size(); } -ark::pandasm::Program *CompilerImpl::Emit(public_lib::Context *context) +void CompilerImpl::Emit(public_lib::Context *context) { HandleContextLiterals(context); @@ -73,8 +73,6 @@ ark::pandasm::Program *CompilerImpl::Emit(public_lib::Context *context) queue_.Consume(); auto *emitter = context->emitter; queue_.Wait([emitter](CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); }); - - return emitter->Finalize(context->config->options->IsDumpDebugInfo(), Signatures::ETS_GLOBAL); } template @@ -354,8 +352,9 @@ static pandasm::Program *EmitProgram(CompilerImpl *compilerImpl, public_lib::Con const CompilationUnit &unit) { ES2PANDA_PERF_SCOPE("@EmitProgram"); + compilerImpl->Emit(context); context->emitter->GenAnnotation(); - auto result = compilerImpl->Emit(context); + auto result = context->emitter->Finalize(context->config->options->IsDumpDebugInfo(), Signatures::ETS_GLOBAL); if (unit.ext == ScriptExtension::ETS && context->compilingState != public_lib::CompilingState::SINGLE_COMPILING) { SavePermanents(context, context->parserProgram); } diff --git a/ets2panda/compiler/core/compilerImpl.h b/ets2panda/compiler/core/compilerImpl.h index 02ac0514b20271e37b69e44adabbb145fdc86da4..d60ffa77cabc647e6222735d16d46d020cf460f6 100644 --- a/ets2panda/compiler/core/compilerImpl.h +++ b/ets2panda/compiler/core/compilerImpl.h @@ -65,7 +65,7 @@ public: static void DumpAsm(const ark::pandasm::Program *prog); static std::string GetPhasesList(ScriptExtension ext); - ark::pandasm::Program *Emit(public_lib::Context *context); + void Emit(public_lib::Context *context); CompileQueue *Queue() { diff --git a/ets2panda/compiler/core/emitter.cpp b/ets2panda/compiler/core/emitter.cpp index f6027fc99ed63e7e3626e81912872d79f1a09e3d..4cee5ca884bf04e27ba394304d60d6b3ec07b14e 100644 --- a/ets2panda/compiler/core/emitter.cpp +++ b/ets2panda/compiler/core/emitter.cpp @@ -22,6 +22,7 @@ #include "compiler/base/literals.h" #include "compiler/core/codeGen.h" #include "compiler/core/regSpiller.h" +#include "compiler/core/ETSemitter.h" #include "compiler/debugger/debuginfoDumper.h" #include "compiler/base/catchTable.h" #include "es2panda.h" @@ -125,6 +126,9 @@ static LiteralPair TransformLiteral(const compiler::Literal *literal) void FunctionEmitter::Generate() { auto *func = GenFunctionSignature(); + if (func == nullptr) { + return; + } GenFunctionInstructions(func); GenVariablesDebugInfo(func); GenSourceFileDebugInfo(func); diff --git a/ets2panda/compiler/core/emitter.h b/ets2panda/compiler/core/emitter.h index 7e2623cc38f6a6f1c37ff01b0aa8caa488a4c1db..fc7aab9650ed5462a5e39f179f2a902156522609 100644 --- a/ets2panda/compiler/core/emitter.h +++ b/ets2panda/compiler/core/emitter.h @@ -18,14 +18,10 @@ #include "compiler/base/literals.h" -#include "util/ustring.h" - -#include -#include -#include +#include #include -#include -#include + +#include "util/ustring.h" namespace ark::pandasm { struct Program; diff --git a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp index 954ab385733b2961e7fe6ffb4ffaf908ae5b67dd..7a4a9db9dda99a3d44b33cfd1cd3a90203fe0ad6 100644 --- a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp @@ -292,6 +292,9 @@ static void GenerateAnonClassTypeFromAbstractClass(public_lib::Context *ctx, ir: std::replace(originalName.begin(), originalName.end(), '.', '$'); auto anonClassName = util::UString(originalName.append(OBJECT_LITERAL_SUFFIX), checker->ProgramAllocator()); auto *classDecl = checker->BuildClass(anonClassName.View(), classBodyBuilder); + if (abstractClassNode->IsDeclare()) { + classDecl->Definition()->AddModifier(ir::ModifierFlags::DECLARE); + } RefineSourceRanges(classDecl); auto *classDef = classDecl->Definition(); if (classDef->TsType()->IsGradualType()) { diff --git a/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp b/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp index a0814250f82eb35d9a3a59af109e855a23479e51..c5ff7503ad86f4fae165dd7547d3dcee580f28a1 100644 --- a/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp +++ b/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp @@ -23,7 +23,7 @@ namespace ark::es2panda::compiler { static void GeneratePartialDeclForExported(const public_lib::Context *const ctx, ir::AstNode *const node) { // NOTE (mmartin): handle interfaces - if (node->IsClassDeclaration()) { + if (node->IsClassDeclaration() && !node->AsClassDeclaration()->Definition()->IsModule()) { ctx->GetChecker()->AsETSChecker()->CreatePartialType(node->AsClassDeclaration()->Definition()->TsType()); } if (node->IsTSInterfaceDeclaration()) { diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 81b369462330b35829cc53c73e1945778f69c393..671ec8b85d45556f059f64b31d7a025b0dc5d282 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -670,7 +670,6 @@ __attribute__((unused)) static Context *GenerateAsm(Context *ctx) ES2PANDA_ASSERT(ctx->state == ES2PANDA_STATE_LOWERED); auto *emitter = ctx->emitter; - emitter->GenAnnotation(); // Handle context literals. uint32_t index = 0; @@ -685,6 +684,7 @@ __attribute__((unused)) static Context *GenerateAsm(Context *ctx) ctx->queue->Consume(); ctx->queue->Wait([emitter](compiler::CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); }); ES2PANDA_ASSERT(ctx->program == nullptr); + emitter->GenAnnotation(); ctx->program = emitter->Finalize(ctx->config->options->IsDumpDebugInfo(), compiler::Signatures::ETS_GLOBAL); ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_ASM_GENERATED : ES2PANDA_STATE_ERROR; return ctx; diff --git a/ets2panda/test/unit/annotations/annotations_emit_test.h b/ets2panda/test/unit/annotations/annotations_emit_test.h index 5b1ea0f04a6b43cf1c0f76291a07bf80154390a8..8b028cc8c4756e960ba970fad76f5b78db290419 100644 --- a/ets2panda/test/unit/annotations/annotations_emit_test.h +++ b/ets2panda/test/unit/annotations/annotations_emit_test.h @@ -17,17 +17,7 @@ #define PANDA_ANNOTATIONS_EMIT_TEST_H #include -#include "annotation.h" -#include "macros.h" -#include "util/options.h" -#include -#include -#include -#include -#include -#include -#include -#include "assembly-program.h" + #include "test/utils/asm_test.h" namespace ark::es2panda::compiler::test { diff --git a/ets2panda/test/unit/annotations/annotations_module.cpp b/ets2panda/test/unit/annotations/annotations_module.cpp index 9039c308a02bbcafb0538cc503002e86a469288b..c7f03de9607f809f1f3dc502b5fbcf42446be810 100644 --- a/ets2panda/test/unit/annotations/annotations_module.cpp +++ b/ets2panda/test/unit/annotations/annotations_module.cpp @@ -14,7 +14,6 @@ */ #include #include -#include #include #include "assembly-program.h" #include "test/unit/annotations/annotations_emit_test.h" diff --git a/ets2panda/test/unit/annotations/annotations_retention_policy.cpp b/ets2panda/test/unit/annotations/annotations_retention_policy.cpp index c7d18c79bed7f4147b46de7e8fb35130de709704..cf1f1ca6505f582c27d329a666da0f5e94666ffe 100644 --- a/ets2panda/test/unit/annotations/annotations_retention_policy.cpp +++ b/ets2panda/test/unit/annotations/annotations_retention_policy.cpp @@ -12,10 +12,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include + #include -#include -#include + +#include + #include "assembly-program.h" #include "test/unit/annotations/annotations_emit_test.h" diff --git a/ets2panda/test/unit/annotations/mutiple_annotations_for_class.cpp b/ets2panda/test/unit/annotations/mutiple_annotations_for_class.cpp index 68f1b30f6ef830bda7bb983acb5ac3be05f1ebd6..32d93cafaa7727382f69b9de6a4c6aec3ae4f59e 100644 --- a/ets2panda/test/unit/annotations/mutiple_annotations_for_class.cpp +++ b/ets2panda/test/unit/annotations/mutiple_annotations_for_class.cpp @@ -78,24 +78,23 @@ public: void CheckLiteralArrayTable(pandasm::Program *program) { - std::vector>> expectedLiteralArrayTable = { - {"ETSGLOBAL%%annotation-Anno2-color-0", std::vector {COLOR_0, COLOR_1}}, - {"ETSGLOBAL%%annotation-Anno2-reviewers-1", - std::vector {std::string("Bob"), std::string("Jim"), std::string("Tom")}}, - {"A%%annotation-Anno2-color-2", std::vector {COLOR_0, COLOR_1}}, - {"A%%annotation-Anno2-reviewers-3", - std::vector {std::string("Bob"), std::string("Jim"), std::string("Tom")}}, - {"A%%annotation-Anno3-reviewersAge-4", - std::vector {REVIEWER_AGE_19, REVIEWER_AGE_20, REVIEWER_AGE_24}}, - {"A%%annotation-Anno3-testBools-5", std::vector {true, true, true}}, - {"A%%annotation-Anno3-mutiArray-6", std::vector {VALUE_9, VALUE_8, VALUE_7}}, - {"A%%annotation-Anno3-mutiArray-7", std::vector {VALUE_6, VALUE_5, VALUE_4}}, - {"A%%annotation-Anno3-mutiArray-8", std::vector {VALUE_3, VALUE_2, VALUE_1}}, + ExpectedLiteralArrayTable const expectedLiteralArrayTable = { + {"ETSGLOBAL%%annotation-Anno2-color-0", {COLOR_0, COLOR_1}}, + {"ETSGLOBAL%%annotation-Anno2-reviewers-1", {"Bob", "Jim", "Tom"}}, + {"A%%annotation-Anno2-color-2", {COLOR_0, COLOR_1}}, + {"A%%annotation-Anno2-reviewers-3", {"Bob", "Jim", "Tom"}}, + {"A%%annotation-Anno3-reviewersAge-4", {REVIEWER_AGE_19, REVIEWER_AGE_20, REVIEWER_AGE_24}}, + {"A%%annotation-Anno3-testBools-5", {true, true, true}}, + {"A%%annotation-Anno3-mutiArray-6", {VALUE_9, VALUE_8, VALUE_7}}, + {"A%%annotation-Anno3-mutiArray-7", {VALUE_6, VALUE_5, VALUE_4}}, + {"A%%annotation-Anno3-mutiArray-8", {VALUE_3, VALUE_2, VALUE_1}}, {"A%%annotation-Anno3-mutiArray-9", - std::vector {std::string("A%%annotation-Anno3-mutiArray-6"), - std::string("A%%annotation-Anno3-mutiArray-7"), - std::string("A%%annotation-Anno3-mutiArray-8")}}}; - + { + "A%%annotation-Anno3-mutiArray-6", + "A%%annotation-Anno3-mutiArray-7", + "A%%annotation-Anno3-mutiArray-8", + }}, + }; AnnotationEmitTest::CheckLiteralArrayTable(program, expectedLiteralArrayTable); } diff --git a/ets2panda/test/unit/annotations/mutiple_annotations_for_function.cpp b/ets2panda/test/unit/annotations/mutiple_annotations_for_function.cpp index 8d74727e6fc2a69058b71869d91c3fe8699b891c..c18401b607786ae5d335a639f8373d1a1fdb2a9f 100644 --- a/ets2panda/test/unit/annotations/mutiple_annotations_for_function.cpp +++ b/ets2panda/test/unit/annotations/mutiple_annotations_for_function.cpp @@ -91,47 +91,39 @@ public: void CheckLiteralArrayTable(pandasm::Program *program) { - std::vector>> expectedLiteralArrayTable = { - {"ETSGLOBAL%%annotation-Anno2-param-0", std::vector {1U, 2U, 3U, 4U}}, - {"ETSGLOBAL%%annotation-Anno3-param-1", std::vector {1U}}, - {"ETSGLOBAL%%annotation-Anno3-param-2", std::vector {2U}}, + ExpectedLiteralArrayTable expectedLiteralArrayTable = { + {"ETSGLOBAL%%annotation-Anno2-param-0", {1U, 2U, 3U, 4U}}, + {"ETSGLOBAL%%annotation-Anno3-param-1", {1U}}, + {"ETSGLOBAL%%annotation-Anno3-param-2", {2U}}, {"ETSGLOBAL%%annotation-Anno3-param-3", - std::vector {std::string("ETSGLOBAL%%annotation-Anno3-param-1"), - std::string("ETSGLOBAL%%annotation-Anno3-param-2")}}, - {"ETSGLOBAL%%annotation-Anno3-param-4", std::vector {2U}}, - {"ETSGLOBAL%%annotation-Anno3-param-5", std::vector {3U}}, + {"ETSGLOBAL%%annotation-Anno3-param-1", "ETSGLOBAL%%annotation-Anno3-param-2"}}, + {"ETSGLOBAL%%annotation-Anno3-param-4", {2U}}, + {"ETSGLOBAL%%annotation-Anno3-param-5", {3U}}, {"ETSGLOBAL%%annotation-Anno3-param-6", - std::vector {std::string("ETSGLOBAL%%annotation-Anno3-param-4"), - std::string("ETSGLOBAL%%annotation-Anno3-param-5")}}, - {"ETSGLOBAL%%annotation-Anno3-param-7", std::vector {3U}}, - {"ETSGLOBAL%%annotation-Anno3-param-8", std::vector {4U}}, + {"ETSGLOBAL%%annotation-Anno3-param-4", "ETSGLOBAL%%annotation-Anno3-param-5"}}, + {"ETSGLOBAL%%annotation-Anno3-param-7", {3U}}, + {"ETSGLOBAL%%annotation-Anno3-param-8", {4U}}, {"ETSGLOBAL%%annotation-Anno3-param-9", - std::vector {std::string("ETSGLOBAL%%annotation-Anno3-param-7"), - std::string("ETSGLOBAL%%annotation-Anno3-param-8")}}, + {"ETSGLOBAL%%annotation-Anno3-param-7", "ETSGLOBAL%%annotation-Anno3-param-8"}}, {"ETSGLOBAL%%annotation-Anno3-param-10", - std::vector {std::string("ETSGLOBAL%%annotation-Anno3-param-3"), - std::string("ETSGLOBAL%%annotation-Anno3-param-6"), - std::string("ETSGLOBAL%%annotation-Anno3-param-9")}}, - {"ETSGLOBAL.foo:void;%%annotation-Anno2-value-11", std::vector {4U, 5U, 6U, 7U}}, - {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-12", std::vector {1U}}, - {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-13", std::vector {2U}}, + {"ETSGLOBAL%%annotation-Anno3-param-3", "ETSGLOBAL%%annotation-Anno3-param-6", + "ETSGLOBAL%%annotation-Anno3-param-9"}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno2-value-11", {4U, 5U, 6U, 7U}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-12", {1U}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-13", {2U}}, {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-14", - std::vector {std::string("ETSGLOBAL.foo:void;%%annotation-Anno3-param-12"), - std::string("ETSGLOBAL.foo:void;%%annotation-Anno3-param-13")}}, - {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-15", std::vector {2U}}, - {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-16", std::vector {3U}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-12", "ETSGLOBAL.foo:void;%%annotation-Anno3-param-13"}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-15", {2U}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-16", {3U}}, {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-17", - std::vector {std::string("ETSGLOBAL.foo:void;%%annotation-Anno3-param-15"), - std::string("ETSGLOBAL.foo:void;%%annotation-Anno3-param-16")}}, - {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-18", std::vector {3U}}, - {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-19", std::vector {4U}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-15", "ETSGLOBAL.foo:void;%%annotation-Anno3-param-16"}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-18", {3U}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-19", {4U}}, {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-20", - std::vector {std::string("ETSGLOBAL.foo:void;%%annotation-Anno3-param-18"), - std::string("ETSGLOBAL.foo:void;%%annotation-Anno3-param-19")}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-18", "ETSGLOBAL.foo:void;%%annotation-Anno3-param-19"}}, {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-21", - std::vector {std::string("ETSGLOBAL.foo:void;%%annotation-Anno3-param-14"), - std::string("ETSGLOBAL.foo:void;%%annotation-Anno3-param-17"), - std::string("ETSGLOBAL.foo:void;%%annotation-Anno3-param-20")}}, + {"ETSGLOBAL.foo:void;%%annotation-Anno3-param-14", "ETSGLOBAL.foo:void;%%annotation-Anno3-param-17", + "ETSGLOBAL.foo:void;%%annotation-Anno3-param-20"}}, }; AnnotationEmitTest::CheckLiteralArrayTable(program, expectedLiteralArrayTable); @@ -142,7 +134,7 @@ private: NO_MOVE_SEMANTIC(MutipleAnnotationsforFunction); }; -TEST_F(MutipleAnnotationsforFunction, mutiple_annotations_for_function) +TEST_F(MutipleAnnotationsforFunction, DISABLED_mutiple_annotations_for_function) { std::string_view text = R"( @interface Anno1 { diff --git a/ets2panda/test/unit/annotations/standard_test.cpp b/ets2panda/test/unit/annotations/standard_test.cpp index 5d22aed167e3f107514f200766663900c0ba6200..6d7a785e6169e8c1c94e8ab5760293aff7e6cffb 100644 --- a/ets2panda/test/unit/annotations/standard_test.cpp +++ b/ets2panda/test/unit/annotations/standard_test.cpp @@ -13,17 +13,13 @@ * limitations under the License. */ #include -#include "annotation.h" -#include "util/options.h" -#include -#include -#include #include #include -#include #include +#include "assembly-literals.h" #include "assembly-program.h" #include "test/unit/annotations/annotations_emit_test.h" +#include "test/utils/asm_test.h" namespace ark::es2panda::compiler::test { @@ -46,23 +42,25 @@ public: void CheckAnnotations(pandasm::Program *program) { + ASSERT_NE(program, nullptr); const std::string annoName = "ClassAuthor"; const std::vector> expectedAnnotations = { {"authorName", "Jim"}, {"authorAge", "35.000000"}, {"testBool", "0"}, {"favorColor", "1"}, - {"color", "ETSGLOBAL%%annotation-ClassAuthor-color-0"}, - {"reviewers", "ETSGLOBAL%%annotation-ClassAuthor-reviewers-1"}, - {"reviewersAge", "ETSGLOBAL%%annotation-ClassAuthor-reviewersAge-2"}, - {"testBools", "ETSGLOBAL%%annotation-ClassAuthor-testBools-3"}, - {"mutiArray", "ETSGLOBAL%%annotation-ClassAuthor-mutiArray-7"}, + {"color", "ETSGLOBAL%%annotation-ClassAuthor-color-8"}, + {"reviewers", "ETSGLOBAL%%annotation-ClassAuthor-reviewers-9"}, + {"reviewersAge", "ETSGLOBAL%%annotation-ClassAuthor-reviewersAge-10"}, + {"testBools", "ETSGLOBAL%%annotation-ClassAuthor-testBools-11"}, + {"mutiArray", "ETSGLOBAL%%annotation-ClassAuthor-mutiArray-15"}, }; AnnotationEmitTest::CheckAnnoDecl(program, annoName, expectedAnnotations); } void CheckClassAnnotations(pandasm::Program *program) { + ASSERT_NE(program, nullptr); const std::string recordName = "MyClass"; const AnnotationMap expectedClassAnnotations = { {"ClassAuthor", @@ -71,11 +69,11 @@ public: {"authorAge", "35.000000"}, {"testBool", "0"}, {"favorColor", "1"}, - {"color", "MyClass%%annotation-ClassAuthor-color-12"}, - {"reviewers", "MyClass%%annotation-ClassAuthor-reviewers-14"}, - {"reviewersAge", "MyClass%%annotation-ClassAuthor-reviewersAge-15"}, - {"testBools", "MyClass%%annotation-ClassAuthor-testBools-13"}, - {"mutiArray", "MyClass%%annotation-ClassAuthor-mutiArray-11"}, + {"color", "MyClass%%annotation-ClassAuthor-color-20"}, + {"reviewers", "MyClass%%annotation-ClassAuthor-reviewers-22"}, + {"reviewersAge", "MyClass%%annotation-ClassAuthor-reviewersAge-23"}, + {"testBools", "MyClass%%annotation-ClassAuthor-testBools-21"}, + {"mutiArray", "MyClass%%annotation-ClassAuthor-mutiArray-19"}, }}, }; AnnotationEmitTest::CheckRecordAnnotations(program, recordName, expectedClassAnnotations); @@ -83,17 +81,18 @@ public: void CheckFunctionAnnotations(pandasm::Program *program) { + ASSERT_NE(program, nullptr); const std::string functionName = "MyClass.foo:void;"; const AnnotationMap expectedFuncAnnotations = { {"ClassAuthor", { - {"mutiArray", "MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-19"}, - {"color", "MyClass.foo:void;%%annotation-ClassAuthor-color-20"}, - {"testBools", "MyClass.foo:void;%%annotation-ClassAuthor-testBools-21"}, - {"reviewers", "MyClass.foo:void;%%annotation-ClassAuthor-reviewers-22"}, + {"mutiArray", "MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-3"}, + {"color", "MyClass.foo:void;%%annotation-ClassAuthor-color-4"}, + {"testBools", "MyClass.foo:void;%%annotation-ClassAuthor-testBools-5"}, + {"reviewers", "MyClass.foo:void;%%annotation-ClassAuthor-reviewers-6"}, {"favorColor", "1"}, {"testBool", "0"}, - {"reviewersAge", "MyClass.foo:void;%%annotation-ClassAuthor-reviewersAge-23"}, + {"reviewersAge", "MyClass.foo:void;%%annotation-ClassAuthor-reviewersAge-7"}, {"authorAge", "35.000000"}, {"authorName", "Jim"}, }}, @@ -103,76 +102,40 @@ public: void CheckLiteralArrayTable(pandasm::Program *program) { - std::vector>> expectedLiteralArrayTable = { - {"ETSGLOBAL%%annotation-ClassAuthor-color-0", - std::vector {COLOR_OPTION_0, COLOR_OPTION_1}}, - {"ETSGLOBAL%%annotation-ClassAuthor-reviewers-1", - std::vector {std::string("Bob"), std::string("Jim"), std::string("Tom")}}, - {"ETSGLOBAL%%annotation-ClassAuthor-reviewersAge-2", - std::vector {AGE_18, AGE_21, AGE_32}}, - {"ETSGLOBAL%%annotation-ClassAuthor-testBools-3", std::vector {false, true, false}}, - {"ETSGLOBAL%%annotation-ClassAuthor-mutiArray-4", - std::vector {VALUE_1, VALUE_2, VALUE_3}}, - {"ETSGLOBAL%%annotation-ClassAuthor-mutiArray-5", - std::vector {VALUE_4, VALUE_5, VALUE_6}}, - {"ETSGLOBAL%%annotation-ClassAuthor-mutiArray-6", - std::vector {VALUE_7, VALUE_8, VALUE_9}}, - {"ETSGLOBAL%%annotation-ClassAuthor-mutiArray-7", - std::vector {std::string("ETSGLOBAL%%annotation-ClassAuthor-mutiArray-4"), - std::string("ETSGLOBAL%%annotation-ClassAuthor-mutiArray-5"), - std::string("ETSGLOBAL%%annotation-ClassAuthor-mutiArray-6")}}, - {"MyClass%%annotation-ClassAuthor-color-12", - std::vector {COLOR_OPTION_0, COLOR_OPTION_1}}, - {"MyClass%%annotation-ClassAuthor-reviewers-14", - std::vector {std::string("Bob"), std::string("Jim"), std::string("Tom")}}, - {"MyClass%%annotation-ClassAuthor-reviewersAge-15", - std::vector {AGE_18, AGE_21, AGE_32}}, - {"MyClass%%annotation-ClassAuthor-testBools-13", std::vector {false, true, false}}, - {"MyClass%%annotation-ClassAuthor-mutiArray-8", - std::vector {VALUE_1, VALUE_2, VALUE_3}}, - {"MyClass%%annotation-ClassAuthor-mutiArray-9", - std::vector {VALUE_4, VALUE_5, VALUE_6}}, - {"MyClass%%annotation-ClassAuthor-mutiArray-10", - std::vector {VALUE_7, VALUE_8, VALUE_9}}, - }; - - std::vector>> remainingExpectedValues = - GetRemainingExpectedValues(); - expectedLiteralArrayTable.insert(expectedLiteralArrayTable.end(), remainingExpectedValues.begin(), - remainingExpectedValues.end()); - - AnnotationEmitTest::CheckLiteralArrayTable(program, expectedLiteralArrayTable); - } - - // After the new name mangling names, the expected values array was too long to fit the 50 lines rule. - std::vector>> GetRemainingExpectedValues() - { - std::vector>> expectedArray = { - {"MyClass%%annotation-ClassAuthor-mutiArray-11", - std::vector {std::string("MyClass%%annotation-ClassAuthor-mutiArray-8"), - std::string("MyClass%%annotation-ClassAuthor-mutiArray-9"), - std::string("MyClass%%annotation-ClassAuthor-mutiArray-10")}}, - {"MyClass.foo:void;%%annotation-ClassAuthor-color-20", - std::vector {COLOR_OPTION_0, COLOR_OPTION_1}}, - {"MyClass.foo:void;%%annotation-ClassAuthor-reviewers-22", - std::vector {std::string("Bob"), std::string("Jim"), std::string("Tom")}}, - {"MyClass.foo:void;%%annotation-ClassAuthor-reviewersAge-23", - std::vector {AGE_18, AGE_21, AGE_32}}, - {"MyClass.foo:void;%%annotation-ClassAuthor-testBools-21", - std::vector {false, true, false}}, - {"MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-16", - std::vector {VALUE_1, VALUE_2, VALUE_3}}, - {"MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-17", - std::vector {VALUE_4, VALUE_5, VALUE_6}}, - {"MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-18", - std::vector {VALUE_7, VALUE_8, VALUE_9}}, - {"MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-19", - std::vector {std::string("MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-16"), - std::string("MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-17"), - std::string("MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-18")}}, + ASSERT_NE(program, nullptr); + using namespace ::test::utils::builder; + + // In case of an error, the test will display the actual initialization list, + // which you need to copy and paste to update the variable value. + // clang-format off + pandasm::Program::LiteralArrayTableT const EXPECTED_LITERAL_ARRAY = { + {"ETSGLOBAL%%annotation-ClassAuthor-color-8", LA({ {0x0_T, 2_U8}, {0x2_T, 0_U32}, {0x0_T, 2_U8}, {0x2_T, 1_U32} })}, + {"ETSGLOBAL%%annotation-ClassAuthor-mutiArray-12", LA({ {0x0_T, 4_U8}, {0x4_T, 1.000000}, {0x0_T, 4_U8}, {0x4_T, 2.000000}, {0x0_T, 4_U8}, {0x4_T, 3.000000} })}, + {"ETSGLOBAL%%annotation-ClassAuthor-mutiArray-13", LA({ {0x0_T, 4_U8}, {0x4_T, 4.000000}, {0x0_T, 4_U8}, {0x4_T, 5.000000}, {0x0_T, 4_U8}, {0x4_T, 6.000000} })}, + {"ETSGLOBAL%%annotation-ClassAuthor-mutiArray-14", LA({ {0x0_T, 4_U8}, {0x4_T, 7.000000}, {0x0_T, 4_U8}, {0x4_T, 8.000000}, {0x0_T, 4_U8}, {0x4_T, 9.000000} })}, + {"ETSGLOBAL%%annotation-ClassAuthor-mutiArray-15", LA({ {0x0_T, 25_U8}, {0x19_T, "ETSGLOBAL%%annotation-ClassAuthor-mutiArray-12"}, {0x0_T, 25_U8}, {0x19_T, "ETSGLOBAL%%annotation-ClassAuthor-mutiArray-13"}, {0x0_T, 25_U8}, {0x19_T, "ETSGLOBAL%%annotation-ClassAuthor-mutiArray-14"} })}, + {"ETSGLOBAL%%annotation-ClassAuthor-reviewers-9", LA({ {0x0_T, 5_U8}, {0x5_T, "Bob"}, {0x0_T, 5_U8}, {0x5_T, "Jim"}, {0x0_T, 5_U8}, {0x5_T, "Tom"} })}, + {"ETSGLOBAL%%annotation-ClassAuthor-reviewersAge-10", LA({ {0x0_T, 4_U8}, {0x4_T, 18.000000}, {0x0_T, 4_U8}, {0x4_T, 21.000000}, {0x0_T, 4_U8}, {0x4_T, 32.000000} })}, + {"ETSGLOBAL%%annotation-ClassAuthor-testBools-11", LA({ {0x0_T, 1_U8}, {0x1_T, false}, {0x0_T, 1_U8}, {0x1_T, true}, {0x0_T, 1_U8}, {0x1_T, false} })}, + {"MyClass%%annotation-ClassAuthor-color-20", LA({ {0x0_T, 2_U8}, {0x2_T, 0_U32}, {0x0_T, 2_U8}, {0x2_T, 1_U32} })}, + {"MyClass%%annotation-ClassAuthor-mutiArray-16", LA({ {0x0_T, 4_U8}, {0x4_T, 1.000000}, {0x0_T, 4_U8}, {0x4_T, 2.000000}, {0x0_T, 4_U8}, {0x4_T, 3.000000} })}, + {"MyClass%%annotation-ClassAuthor-mutiArray-17", LA({ {0x0_T, 4_U8}, {0x4_T, 4.000000}, {0x0_T, 4_U8}, {0x4_T, 5.000000}, {0x0_T, 4_U8}, {0x4_T, 6.000000} })}, + {"MyClass%%annotation-ClassAuthor-mutiArray-18", LA({ {0x0_T, 4_U8}, {0x4_T, 7.000000}, {0x0_T, 4_U8}, {0x4_T, 8.000000}, {0x0_T, 4_U8}, {0x4_T, 9.000000} })}, + {"MyClass%%annotation-ClassAuthor-mutiArray-19", LA({ {0x0_T, 25_U8}, {0x19_T, "MyClass%%annotation-ClassAuthor-mutiArray-16"}, {0x0_T, 25_U8}, {0x19_T, "MyClass%%annotation-ClassAuthor-mutiArray-17"}, {0x0_T, 25_U8}, {0x19_T, "MyClass%%annotation-ClassAuthor-mutiArray-18"} })}, + {"MyClass%%annotation-ClassAuthor-reviewers-22", LA({ {0x0_T, 5_U8}, {0x5_T, "Bob"}, {0x0_T, 5_U8}, {0x5_T, "Jim"}, {0x0_T, 5_U8}, {0x5_T, "Tom"} })}, + {"MyClass%%annotation-ClassAuthor-reviewersAge-23", LA({ {0x0_T, 4_U8}, {0x4_T, 18.000000}, {0x0_T, 4_U8}, {0x4_T, 21.000000}, {0x0_T, 4_U8}, {0x4_T, 32.000000} })}, + {"MyClass%%annotation-ClassAuthor-testBools-21", LA({ {0x0_T, 1_U8}, {0x1_T, false}, {0x0_T, 1_U8}, {0x1_T, true}, {0x0_T, 1_U8}, {0x1_T, false} })}, + {"MyClass.foo:void;%%annotation-ClassAuthor-color-4", LA({ {0x0_T, 2_U8}, {0x2_T, 0_U32}, {0x0_T, 2_U8}, {0x2_T, 1_U32} })}, + {"MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-0", LA({ {0x0_T, 4_U8}, {0x4_T, 1.000000}, {0x0_T, 4_U8}, {0x4_T, 2.000000}, {0x0_T, 4_U8}, {0x4_T, 3.000000} })}, + {"MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-1", LA({ {0x0_T, 4_U8}, {0x4_T, 4.000000}, {0x0_T, 4_U8}, {0x4_T, 5.000000}, {0x0_T, 4_U8}, {0x4_T, 6.000000} })}, + {"MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-2", LA({ {0x0_T, 4_U8}, {0x4_T, 7.000000}, {0x0_T, 4_U8}, {0x4_T, 8.000000}, {0x0_T, 4_U8}, {0x4_T, 9.000000} })}, + {"MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-3", LA({ {0x0_T, 25_U8}, {0x19_T, "MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-0"}, {0x0_T, 25_U8}, {0x19_T, "MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-1"}, {0x0_T, 25_U8}, {0x19_T, "MyClass.foo:void;%%annotation-ClassAuthor-mutiArray-2"} })}, + {"MyClass.foo:void;%%annotation-ClassAuthor-reviewers-6", LA({ {0x0_T, 5_U8}, {0x5_T, "Bob"}, {0x0_T, 5_U8}, {0x5_T, "Jim"}, {0x0_T, 5_U8}, {0x5_T, "Tom"} })}, + {"MyClass.foo:void;%%annotation-ClassAuthor-reviewersAge-7", LA({ {0x0_T, 4_U8}, {0x4_T, 18.000000}, {0x0_T, 4_U8}, {0x4_T, 21.000000}, {0x0_T, 4_U8}, {0x4_T, 32.000000} })}, + {"MyClass.foo:void;%%annotation-ClassAuthor-testBools-5", LA({ {0x0_T, 1_U8}, {0x1_T, false}, {0x0_T, 1_U8}, {0x1_T, true}, {0x0_T, 1_U8}, {0x1_T, false} })}, }; - - return expectedArray; + // clang-format on + ExpectLiteralArrayTable(program, EXPECTED_LITERAL_ARRAY); } private: diff --git a/ets2panda/test/unit/extern_flag_test.cpp b/ets2panda/test/unit/extern_flag_test.cpp index 85b3fd21adfed71a70e7a3bb921a0010fdd8b93d..3afd82b2bccaf3be6aecb4c86c5b5a65ae937c67 100644 --- a/ets2panda/test/unit/extern_flag_test.cpp +++ b/ets2panda/test/unit/extern_flag_test.cpp @@ -14,17 +14,73 @@ */ #include +#include +#include #include "assembler/assembly-program.h" +#include "assembly-function.h" +#include "assembly-record.h" #include "generated/signatures.h" +#include "gmock/gmock.h" #include "libpandabase/mem/mem.h" #include "macros.h" #include "mem/pool_manager.h" #include "util/options.h" #include "test/utils/asm_test.h" +namespace { + +inline bool FunctionExternalFlag(ark::pandasm::Function const &fn) +{ + return fn.metadata->GetAttribute("external"); +} + +inline bool RecordExternalFlag(ark::pandasm::Record const &record) +{ + return record.metadata->GetAttribute("external"); +} + +struct BoolAlpha final { + explicit BoolAlpha(std::ostream &s) : s_ {s}, f_ {s.setf(std::ios_base::boolalpha)} {} + ~BoolAlpha() + { + s_.setf(f_); + } + +private: + std::ostream &s_; + std::ios_base::fmtflags f_; +}; + +} // namespace + +namespace ark::pandasm { + +// The value printer for expects. +std::ostream &operator<<(std::ostream &s, const Function &arg) +{ + BoolAlpha const boolAplpha {s}; + return s << "Function{" << std::quoted(arg.name) << ", external=" << FunctionExternalFlag(arg) << "}"; +} + +// The value printer for expects. +std::ostream &operator<<(std::ostream &s, const Record &arg) +{ + BoolAlpha const boolAplpha {s}; + return s << "Function{" << std::quoted(arg.name) << ", external=" << RecordExternalFlag(arg) << "}"; +} + +} // namespace ark::pandasm + namespace ark::es2panda::compiler::test { +MATCHER_P(ExternAttribute, flag, "") +{ + bool value = arg.metadata->GetAttribute("external"); + *result_listener << "'external' attribute is " << value; + return value == flag; +} + class DeclareTest : public testing::Test { public: DeclareTest() @@ -38,6 +94,12 @@ public: mem::MemConfig::Finalize(); } +protected: + pandasm::Program const &Program() const + { + return *program_; + } + void SetCurrentProgram(std::string_view src) { static constexpr std::string_view FILE_NAME = "ets_decl_test.ets"; @@ -45,43 +107,36 @@ public: "--ets-unnamed"}; // NOLINT(modernize-avoid-c-arrays) program_ = GetProgram({args.data(), args.size()}, FILE_NAME, src); - ASSERT_NE(program_.get(), nullptr); } - void CheckRecordExternalFlag(std::string_view recordName) + void CheckRecordExternalFlag(std::string recordName, bool externFlag = true) { - pandasm::Record *record = GetRecord(recordName, program_); - ASSERT_TRUE(record != nullptr) << "Record '" << recordName << "' not found"; - ASSERT_TRUE(HasExternalFlag(record)) << "Record '" << record->name << "' doesn't have External flag"; + ASSERT_NE(program_, nullptr); + using namespace ::testing; + auto const matcher = Contains(Pair(recordName, ExternAttribute(externFlag))); + EXPECT_THAT(program_->recordTable, matcher); } - void CheckFunctionExternalFlag(std::string_view functionName, bool isStatic = false) + void CheckFunctionExternalFlag(std::string functionName, bool isStatic = false, bool externFlag = true) { - pandasm::Function *fn = - GetFunction(functionName, isStatic ? program_->functionStaticTable : program_->functionInstanceTable); - ASSERT_TRUE(fn != nullptr) << "Function '" << functionName << "' not found"; - ASSERT_TRUE(HasExternalFlag(fn)) << "Function '" << fn->name << "' doesn't have External flag"; + ASSERT_NE(program_, nullptr); + using namespace ::testing; + auto const matcher = Contains(Pair(functionName, ExternAttribute(externFlag))); + if (isStatic) { + EXPECT_THAT(program_->functionStaticTable, matcher); + } else { + EXPECT_THAT(program_->functionInstanceTable, matcher); + } } - void CheckFunctionNoExternalFlag(std::string_view functionName, bool isStatic = false) + void CheckRecordNotExists(std::string name) { - pandasm::Function *fn = - GetFunction(functionName, isStatic ? program_->functionStaticTable : program_->functionInstanceTable); - ASSERT_TRUE(fn != nullptr) << "Function '" << functionName << "' not found"; - ASSERT_FALSE(HasExternalFlag(fn)) << "Function '" << fn->name << "' has External flag"; + ASSERT_NE(program_, nullptr); + using namespace ::testing; + EXPECT_THAT(program_->recordTable, Not(Contains(Key(name)))); } private: - bool HasExternalFlag(pandasm::Function *fn) - { - return (fn->metadata->GetAttribute("external")); - } - - bool HasExternalFlag(pandasm::Record *record) - { - return (record->metadata->GetAttribute("external")); - } - NO_COPY_SEMANTIC(DeclareTest); NO_MOVE_SEMANTIC(DeclareTest); @@ -104,16 +159,17 @@ private: return std::unique_ptr(compiler.Compile(input, *options, de)); } - pandasm::Function *GetFunction(std::string_view functionName, const std::map &table) + pandasm::Function const *GetFunction(std::string_view functionName, + const std::map &table) { auto it = table.find(functionName.data()); if (it == table.end()) { return nullptr; } - return const_cast(&it->second); + return &it->second; } - pandasm::Record *GetRecord(std::string_view recordName, const std::unique_ptr &program) + pandasm::Record const *GetRecord(std::string_view recordName, const std::unique_ptr &program) { auto it = program->recordTable.find(recordName.data()); if (it == program->recordTable.end()) { @@ -150,6 +206,7 @@ TEST_F(DeclareTest, noImplclass_def_with_overload_0) declare class my_class { public foo(arg?: int): string } + function foo(my: my_class){ return my.foo() } )"); CheckFunctionExternalFlag("my_class.foo:std.core.Int;std.core.String;"); } @@ -161,6 +218,7 @@ TEST_F(DeclareTest, class_constructor_without_parameters_0) declare class A_class { static x: double } + let a = new A_class() )"); CheckFunctionExternalFlag("A_class.:void;"); } @@ -171,6 +229,7 @@ TEST_F(DeclareTest, class_constructor_without_parameters_1) declare class A { constructor(); } + let a = new A(); )"); CheckFunctionExternalFlag("A.:void;"); } @@ -180,8 +239,9 @@ TEST_F(DeclareTest, class_implicit_constructor_0) SetCurrentProgram(R"( declare class A { } + let a = new A(); )"); - CheckFunctionExternalFlag("A.:void;"); + CheckFunctionExternalFlag("A.:void;", false); } // === Method of interface === @@ -191,6 +251,7 @@ TEST_F(DeclareTest, noImplinterface_def_with_overload_0) declare interface my_inter { foo(arg?: int): void } + function foo(my: my_inter){ return my.foo() } )"); CheckFunctionExternalFlag("my_inter.foo:std.core.Int;void;"); } @@ -201,7 +262,7 @@ TEST_F(DeclareTest, namespace_0) declare namespace A { } )"); - CheckRecordExternalFlag("A"); + CheckRecordNotExists("A"); } } // namespace ark::es2panda::compiler::test diff --git a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_iv.cpp b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_iv.cpp index e1d8514256ea11979a137a12f919700ce34ad3e3..d773a477fdd225972d9ece2b7ba01675047d9a97 100644 --- a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_iv.cpp +++ b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_iv.cpp @@ -343,23 +343,6 @@ TEST_F(PluginConversionRuleUnitTest, PropertyProcessorInputParameter) EXPECT_TRUE(HasMatched(targetAPIWithNoSpace)); } -// apiName: ETSObjectTypeIterateConst -TEST_F(PluginConversionRuleUnitTest, PropertyTraverserInputParameter) -{ - std::string targetCAPI {R"( - extern "C" void ETSObjectTypeIterateConst([[maybe_unused]] es2panda_Context *context, - es2panda_Type *classInstance, [[maybe_unused]] PropertyTraverser cb/*return_args:*/) - { - std::function cbE2p = - [cb](const varbinder::LocalVariable *propertyTraverserLambdaVariable) - {cb(reinterpret_cast(propertyTraverserLambdaVariable));}; - ((reinterpret_cast(classInstance))->Iterate(cbE2p)); - })"}; - - std::string targetAPIWithNoSpace = RemoveWhitespace(targetCAPI); - EXPECT_TRUE(HasMatched(targetAPIWithNoSpace)); -} - // apiName: CreateTSModuleDeclaration TEST_F(PluginConversionRuleUnitTest, TSModuleDeclarationConstructorFlagsInputParameter) { diff --git a/ets2panda/test/unit/rest_parameter_flag_test.cpp b/ets2panda/test/unit/rest_parameter_flag_test.cpp index dee24643a6b468f509eea8aa9a399afb2e3bd846..82cb1c05e76ffd39eb8bcaf95defc2bc69e8de5e 100644 --- a/ets2panda/test/unit/rest_parameter_flag_test.cpp +++ b/ets2panda/test/unit/rest_parameter_flag_test.cpp @@ -13,16 +13,27 @@ * limitations under the License. */ +#include +#include + #include +#include #include "assembler/assembly-program.h" +#include "assembly-function.h" #include "es2panda.h" -#include "generated/signatures.h" -#include "libpandabase/mem/mem.h" -#include "macros.h" -#include "mem/pool_manager.h" #include "test/utils/asm_test.h" +namespace ark::pandasm { + +// The value printer for expects. +std::ostream &operator<<(std::ostream &s, const Function &arg) +{ + return s << "Function{" << std::quoted(arg.name) << "}"; +} + +} // namespace ark::pandasm + namespace ark::es2panda::compiler::test { class RestParameterTest : public ::test::utils::AsmTest { @@ -323,7 +334,9 @@ TEST_F(RestParameterTest, abstract_function_with_rest_parameter_1) TEST_F(RestParameterTest, external_function_with_rest_parameter_0) { SetCurrentProgram(""); - CheckRestParameterFlag("std.core.LambdaValue.invoke:escompat.Array;std.core.Object;", false); + auto constexpr expected_key = "std.core.Object[].:std.core.Object[];i32;void;"; + using namespace ::testing; + EXPECT_THAT(program_->functionInstanceTable, Contains(Key(Eq(expected_key)))); } TEST_F(RestParameterTest, external_function_with_rest_parameter_1) diff --git a/ets2panda/test/unit/union_emit_test.cpp b/ets2panda/test/unit/union_emit_test.cpp index 13fcd11f6dc862ada91276bff2eb572405887db1..8aacea12524d529853067dcd3fc0870e256a4ed1 100644 --- a/ets2panda/test/unit/union_emit_test.cpp +++ b/ets2panda/test/unit/union_emit_test.cpp @@ -13,9 +13,29 @@ * limitations under the License. */ +#include +#include +#include + #include +#include + +#include "assembly-function.h" +#include "assembly-program.h" + +#include "gmock/gmock.h" #include "test/utils/asm_test.h" +namespace ark::pandasm { + +// The value printer for expects. +std::ostream &operator<<(std::ostream &s, const Function &arg) +{ + return s << std::quoted(arg.name); +} + +} // namespace ark::pandasm + namespace ark::es2panda::compiler::test { class UnionAsmTest : public ::test::utils::AsmTest { @@ -26,28 +46,20 @@ public: void CheckFunction(std::string_view funcSig, bool found = true) { + ASSERT_NE(program_.get(), nullptr); pandasm::Function *func = GetFunction(funcSig, program_->functionStaticTable); if (found) { - ASSERT_TRUE(func != nullptr) << "Function '" << funcSig << "' not found"; + EXPECT_NE(func, nullptr) << "Function '" << funcSig << "' not found"; } else { - ASSERT_TRUE(func == nullptr) << "Function '" << funcSig << "' found"; - } - } - - void CheckUnionType(std::string_view recordName, bool found = true) - { - pandasm::Record *rec = GetRecord(recordName, program_); - if (found) { - ASSERT_TRUE(rec != nullptr) << "Type '" << recordName << "' not found"; - } else { - ASSERT_TRUE(rec == nullptr) << "Type '" << recordName << "' found"; + EXPECT_EQ(func, nullptr) << "Function '" << funcSig << "' found"; } } void CheckInsInFunction(std::string_view functionName, std::string_view insString, bool result = true) { + ASSERT_NE(program_.get(), nullptr); pandasm::Function *fn = GetFunction(functionName, program_->functionStaticTable); - ASSERT_TRUE(fn != nullptr) << "Function '" << functionName << "' not found"; + ASSERT_NE(fn, nullptr) << "Function '" << functionName << "' not found"; bool found = false; for (const auto &i : fn->ins) { std::string iStr = i.ToString("", true); @@ -55,8 +67,26 @@ public: found = true; } } - ASSERT_TRUE(found == result) << "Instruction '" << insString << "' in function '" << functionName - << "' not met expectations"; + EXPECT_EQ(found, result) << "Instruction '" << insString << "' in function '" << functionName + << "' not met expectations"; + } + + template + void GetAllParameterTypeNames(Iterator result) + { + ASSERT_NE(program_.get(), nullptr); + for (auto const &pair : program_->functionStaticTable) { + auto const ¶ms = pair.second.params; + std::transform(params.cbegin(), params.cend(), result, + [](auto const ¶m) { return param.type.GetName(); }); + } + } + + void CheckParameterTypes(const std::set &types) + { + std::set paramTypes; + GetAllParameterTypeNames(std::inserter(paramTypes, paramTypes.end())); + EXPECT_THAT(paramTypes, ::testing::ContainerEq(types)); } private: @@ -77,10 +107,12 @@ TEST_F(UnionAsmTest, union_test) function test4(v:B|C|D|int) {} )"); - CheckUnionType("{Udummy.A,dummy.B}"); - CheckUnionType("{Udummy.A,dummy.B,dummy.C[]}"); - CheckUnionType("{Udummy.A,dummy.B,dummy.C}"); - CheckUnionType("{Udummy.B,dummy.C,dummy.D,std.core.Int}"); + CheckParameterTypes({ + "{Udummy.A,dummy.B}", + "{Udummy.A,dummy.B,dummy.C[]}", + "{Udummy.A,dummy.B,dummy.C}", + "{Udummy.B,dummy.C,dummy.D,std.core.Int}", + }); } TEST_F(UnionAsmTest, union_test_extends) @@ -96,9 +128,11 @@ TEST_F(UnionAsmTest, union_test_extends) function test4(v:B|C|D|int) {} )"); - CheckUnionType("{Udummy.A,dummy.B}"); - CheckUnionType("{Udummy.A,dummy.B,dummy.C[]}"); - CheckUnionType("{Udummy.B,std.core.Int}"); + CheckParameterTypes({ + "{Udummy.A,dummy.B}", + "{Udummy.A,dummy.B,dummy.C[]}", + "{Udummy.B,std.core.Int}", + }); } TEST_F(UnionAsmTest, union_test_2) @@ -118,12 +152,16 @@ TEST_F(UnionAsmTest, union_test_2) function test8(v:A|D|D|D) {} )"); - CheckUnionType("{Udummy.A,dummy.B,dummy.C,dummy.D}"); - CheckUnionType("{Udummy.A,dummy.B,dummy.C}"); - CheckUnionType("{Udummy.A,dummy.B}"); - CheckUnionType("{Udummy.A,dummy.D}"); - CheckUnionType("{Udummy.A,std.core.Double}"); - CheckUnionType("{Udummy.B,dummy.C}"); + CheckParameterTypes({ + "{Udummy.A,dummy.B,dummy.C,dummy.D}", + "{Udummy.A,dummy.B,dummy.C}", + "{Udummy.A,dummy.B}", + "{Udummy.A,dummy.D}", + "{Udummy.A,std.core.Double}", + "{Udummy.B,dummy.C}", + "{Ustd.core.Double,std.core.Int,std.core.Long}", + "{Ustd.core.Double,std.core.Long}", + }); } TEST_F(UnionAsmTest, union_test_arrays) @@ -145,31 +183,18 @@ TEST_F(UnionAsmTest, union_test_arrays) function test1(v:FixedArray|FixedArray>|FixedArray|FixedArray) {} )"); - CheckUnionType("{Udummy.A,dummy.B}"); - CheckUnionType("{Udummy.A,dummy.B}[]"); - CheckUnionType("{Udummy.A,dummy.D,std.core.Double}"); - CheckUnionType("{Udummy.A,dummy.D,std.core.Double}[]"); - CheckUnionType("{Udummy.A,dummy.D,std.core.Int}"); - CheckUnionType("{Udummy.A,dummy.D,std.core.Int}[]"); - CheckUnionType("{Udummy.A,dummy.D,std.core.Long}"); - CheckUnionType("{Udummy.A,dummy.D,std.core.Long}[]"); - CheckUnionType("{Udummy.A,dummy.D}"); - CheckUnionType("{Udummy.A,dummy.D}[]"); - CheckUnionType("{Udummy.B,dummy.C,{Udummy.A,dummy.B}[]}"); - CheckUnionType("{Udummy.B,dummy.C,{Udummy.A,dummy.D,std.core.Double}[]}"); - CheckUnionType("{Udummy.B,dummy.C,{Udummy.C,dummy.D}[]}"); - CheckUnionType("{Udummy.B,dummy.C}"); - CheckUnionType("{Udummy.B,dummy.C}[]"); - CheckUnionType("{Udummy.B,dummy.D}"); - CheckUnionType("{Udummy.B,dummy.D}[]"); - CheckUnionType("{Udummy.B,{Udummy.A,dummy.D}[],{Udummy.B,dummy.C}[],{Udummy.B,dummy.D}[],{Udummy.C,dummy.D}[]}"); - CheckUnionType("{Udummy.C,dummy.D}"); - CheckUnionType("{Udummy.C,dummy.D}[]"); - CheckUnionType( - "{U{Udummy.A,dummy.D,std.core.Double}[],{Udummy.A,dummy.D,std.core.Int}[],{Udummy.A,dummy.D,std.core.Long}[]}"); - CheckUnionType("{U{Udummy.A,dummy.D}[],{Udummy.B,dummy.C}[],{Udummy.B,dummy.D}[],{Udummy.C,dummy.D}[]}"); - CheckUnionType("{U{Udummy.A,dummy.D}[],{Udummy.B,dummy.D}[]}"); - CheckUnionType("{U{Udummy.B,dummy.C}[],{Udummy.C,dummy.D}[]}"); + CheckParameterTypes({ + "{Udummy.B,dummy.C,{Udummy.A,dummy.B}[]}", + "{Udummy.B,dummy.C,{Udummy.A,dummy.D,std.core.Double}[]}", + "{Udummy.B,dummy.C,{Udummy.C,dummy.D}[]}", + "{Udummy.B,{Udummy.A,dummy.D}[],{Udummy.B,dummy.C}[],{Udummy.B,dummy.D}[],{Udummy.C,dummy.D}[]}", + "{U{Udummy.A,dummy.D,std.core.Double}[],{Udummy.A,dummy.D,std.core.Int}[],{Udummy.A,dummy.D,std.core.Long}[]}", + "{U{Udummy.A,dummy.D}[],{Udummy.B,dummy.C}[],{Udummy.B,dummy.D}[],{Udummy.C,dummy.D}[]}", + "{U{Udummy.A,dummy.D}[],{Udummy.B,dummy.D}[]}", + "{U{Udummy.B,dummy.C}[],{Udummy.C,dummy.D}[]}", + "{Uf64[],i64[],{Uf64[],i32[]}[]}", + "{Ustd.core.Double,std.core.Long,{Ustd.core.Double,std.core.Int}[]}", + }); } TEST_F(UnionAsmTest, union_test_null) @@ -182,7 +207,9 @@ TEST_F(UnionAsmTest, union_test_null) function test1(v:D|C|B|null|A) {} )"); - CheckUnionType("{Udummy.A,dummy.B,dummy.C,dummy.D,std.core.Null}"); + CheckParameterTypes({ + "{Udummy.A,dummy.B,dummy.C,dummy.D,std.core.Null}", + }); } TEST_F(UnionAsmTest, union_test_undefined) @@ -197,9 +224,11 @@ TEST_F(UnionAsmTest, union_test_undefined) function test3(v:undefined|A|null) {} )"); - CheckUnionType("{Udummy.A,dummy.B,dummy.C,dummy.D}"); - CheckUnionType("{Udummy.A,undefined}", false); - CheckUnionType("{Udummy.A,std.core.Null}"); + CheckParameterTypes({ + "{Udummy.A,dummy.B,dummy.C,dummy.D}", + "dummy.A", + "{Udummy.A,std.core.Null}", + }); } TEST_F(UnionAsmTest, union_test_isinstanceof) diff --git a/ets2panda/test/utils/asm_test.cpp b/ets2panda/test/utils/asm_test.cpp index 2d15e56dc65037419e3d911516a792a779064aba..f33d6f6f90d65986f799496399f9b43517f1f1b3 100644 --- a/ets2panda/test/utils/asm_test.cpp +++ b/ets2panda/test/utils/asm_test.cpp @@ -12,13 +12,122 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include #include +#include +#include +#include +#include + +#include + #include "asm_test.h" #include "assembly-field.h" +#include "assembly-literals.h" +#include "assembly-program.h" + +#include "generated/signatures.h" +#include "gmock/gmock.h" +#include "libarkfile/literal_data_accessor.h" + +// Value printers for tests +namespace ark::pandasm { + +namespace { + +template +struct overloaded : Ts... { + using Ts::operator()...; +}; + +// explicit deduction guide (not needed as of C++20) +template +overloaded(Ts...) -> overloaded; + +} // namespace + +[[maybe_unused]] static std::ostream &operator<<(std::ostream &s, decltype(LiteralArray::Literal::value) const &value) +{ + std::visit(overloaded { + [&s](bool v) { s << (v ? "true" : "false"); }, + [&s](uint8_t v) { s << std::to_string(v) << "_U8"; }, + [&s](uint16_t v) { s << std::to_string(v) << "_U16"; }, + [&s](uint32_t v) { s << std::to_string(v) << "_U32"; }, + [&s](uint64_t v) { s << std::to_string(v) << "_U64"; }, + [&s](float v) { s << std::fixed << v << std::defaultfloat << "f"; }, + [&s](double v) { s << std::fixed << v << std::defaultfloat; }, + [&s](const std::string &v) { s << std::quoted(v); }, + }, + value); + return s; +} + +[[maybe_unused]] static std::ostream &operator<<(std::ostream &s, panda_file::LiteralTag const &value) +{ + return s << "0x" << std::hex << uint64_t(value) << std::dec << "_T"; +} + +[[maybe_unused]] static std::ostream &operator<<(std::ostream &s, LiteralArray::Literal const &value) +{ + return s << "{" << value.tag << ", " << value.value << "}"; +} + +[[maybe_unused]] static std::ostream &operator<<(std::ostream &s, LiteralArray const &value) +{ + s << "LA({ "; + auto it = value.literals.begin(); + if (it != value.literals.end()) { + s << *it++; + } + while (it != value.literals.end()) { + s << ", " << *it++; + } + s << " })"; + return s; +} + +bool operator==(const LiteralArray &lhs, const LiteralArray &rhs) +{ + return lhs.literals == rhs.literals; +} +bool operator==(const LiteralArray::Literal &lhs, const LiteralArray::Literal &rhs) +{ + return lhs.tag == rhs.tag && lhs.value == rhs.value; +} + +using ArrType = Program::LiteralArrayTableT; + +[[maybe_unused]] static std::ostream &operator<<(std::ostream &s, ArrType::value_type const &value) +{ + return s << "{" << std::quoted(value.first) << ", " << value.second << "}"; +} + +[[maybe_unused]] static void PrintTo(const ArrType &value, std::ostream *s) +{ + *s << "{" << std::endl; + for (auto const &p : value) { + *s << " " << p << "," << std::endl; + } + *s << "}" << std::endl; +} + +} // namespace ark::pandasm namespace test::utils { +namespace builder { + +::ark::panda_file::LiteralTag operator""_T(unsigned long long value) +{ + return ::ark::panda_file::LiteralTag(value); +} + +::ark::pandasm::LiteralArray LA(::ark::pandasm::LiteralArray::LiteralVector &&value) +{ + return ::ark::pandasm::LiteralArray {std::move(value)}; +} + +} // namespace builder + AsmTest::AsmTest() { ark::mem::MemConfig::Initialize(0, 0, ark::es2panda::COMPILER_SIZE, 0, 0, 0); @@ -85,15 +194,22 @@ void AsmTest::CheckAnnoDecl(ark::pandasm::Program *program, const std::string &a } } -void AsmTest::CheckLiteralArrayTable( - ark::pandasm::Program *program, - const std::vector>> &expectedLiteralArrayTable) +void AsmTest::ExpectLiteralArrayTable( + ark::pandasm::Program *program, const ::ark::pandasm::Program::LiteralArrayTableT &expectedLiteralArrayTable) const +{ + EXPECT_THAT(program->literalarrayTable, ::testing::ContainerEq(expectedLiteralArrayTable)); +} + +void AsmTest::CheckLiteralArrayTable(ark::pandasm::Program *program, + const AsmTest::ExpectedLiteralArrayTable &expectedLiteralArrayTable) { const auto &literalarrayTable = program->literalarrayTable; ASSERT_FALSE(literalarrayTable.empty()) << "literalarrayTable is empty!"; for (const auto &literalArray : expectedLiteralArrayTable) { + // ASSERT_THAT(literalarrayTable, ::testing::Contains(::testing::Key(literalArray.first))); auto found = literalarrayTable.find(literalArray.first); - ASSERT_NE(found, literalarrayTable.end()); + ASSERT_NE(found, literalarrayTable.end()) << "Not found " << std::quoted(literalArray.first) << std::endl + << "Actual: " << ::testing::PrintToString(literalarrayTable); size_t i = 1; for (const auto &value : literalArray.second) { constexpr int STRIDE = 2; diff --git a/ets2panda/test/utils/asm_test.h b/ets2panda/test/utils/asm_test.h index e58fde52fd5c68e6f7b3dff359a26101a31a28c0..ff7b583aa138062bffe2eb4fe2fb5cf4167dba08 100644 --- a/ets2panda/test/utils/asm_test.h +++ b/ets2panda/test/utils/asm_test.h @@ -16,19 +16,70 @@ #ifndef ES2PANDA_TEST_UTILS_ASM_TEST_H #define ES2PANDA_TEST_UTILS_ASM_TEST_H -#include "compiler/lowering/phase.h" -#include "util/options.h" +#include +#include +#include +#include +#include +#include +#include +#include + #include +#include "assembler/assembly-function.h" +#include "assembler/assembly-record.h" +#include "assembler/assembly-program.h" +#include "assembly-literals.h" +#include "util/diagnosticEngine.h" +#include "util/options.h" + namespace util_alias = ark::es2panda::util; using AnnotationMap = std::map>>; using AnnotationValueType = std::variant; +// helper type for the visitor + +namespace ark::pandasm { + +bool operator==(const LiteralArray &lhs, const LiteralArray &rhs); +bool operator==(const LiteralArray::Literal &lhs, const LiteralArray::Literal &rhs); + +} // namespace ark::pandasm namespace test::utils { +namespace builder { + +::ark::panda_file::LiteralTag operator""_T(unsigned long long value); +::ark::pandasm::LiteralArray LA(::ark::pandasm::LiteralArray::LiteralVector &&value); + +inline uint8_t operator""_U8(unsigned long long value) +{ + return uint8_t(value); +} + +inline uint16_t operator""_U16(unsigned long long value) +{ + return uint16_t(value); +} + +inline uint32_t operator""_U32(unsigned long long value) +{ + return uint32_t(value); +} + +inline uint64_t operator""_U64(unsigned long long value) +{ + return uint64_t(value); +} + +} // namespace builder + class AsmTest : public testing::Test { public: + using ExpectedLiteralArrayTable = std::vector>>; + AsmTest(); ~AsmTest() override; @@ -61,9 +112,10 @@ public: void CheckAnnoDecl(ark::pandasm::Program *program, const std::string &annoName, const std::vector> &expectedAnnotations); - void CheckLiteralArrayTable( - ark::pandasm::Program *program, - const std::vector>> &expectedLiteralArrayTable); + void ExpectLiteralArrayTable(ark::pandasm::Program *program, + const ::ark::pandasm::Program::LiteralArrayTableT &expectedLiteralArrayTable) const; + void CheckLiteralArrayTable(ark::pandasm::Program *program, + const ExpectedLiteralArrayTable &expectedLiteralArrayTable); void CheckAnnotation(const std::vector> &expectedValues, const ark::pandasm::AnnotationData &annotation); diff --git a/ets2panda/test/utils/checker_test.h b/ets2panda/test/utils/checker_test.h index 69f1fbdee00b0144e41b12514131388ff45479b0..1039ff65c15e4ac4f0907ed8d015f2e1e793a31a 100644 --- a/ets2panda/test/utils/checker_test.h +++ b/ets2panda/test/utils/checker_test.h @@ -230,7 +230,11 @@ public: publicContext_->codeGenCb = MakeCompileJob(); ark::es2panda::compiler::CompilerImpl compilerImpl(options->GetThread(), {}); - return compilerImpl.Emit(publicContext_.get()); + + compilerImpl.Emit(publicContext_.get()); + publicContext_->emitter->GenAnnotation(); + return publicContext_->emitter->Finalize(publicContext_->config->options->IsDumpDebugInfo(), + ark::es2panda::compiler::Signatures::ETS_GLOBAL); } NO_COPY_SEMANTIC(CheckerTest); NO_MOVE_SEMANTIC(CheckerTest); diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index 29652fc113745c590cac6c57fce26e109b7681c6..3af0f33c12de3638e60bd6aa3ae1fc67c7bf67a2 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -15,6 +15,7 @@ #include "ETSBinder.h" +#include "es2panda.h" #include "evaluate/scopedDebugInfoPlugin.h" #include "public/public.h" #include "compiler/lowering/util.h" @@ -1287,6 +1288,11 @@ void ETSBinder::AddCompilableFunction(ir::ScriptFunction *func) return; } + if (GetContext()->config->options->GetCompilationMode() == CompilationMode::GEN_ABC_FOR_EXTERNAL_SOURCE && + func->Scope()->Name().Is(compiler::Signatures::ETS_GLOBAL)) { + return; + } + AddCompilableFunctionScope(func->Scope()); }