diff --git a/arkguard/package.json b/arkguard/package.json index 63a0d20c97f8011fe3f6463e5772940c7b8fb8d3..d515ee3042d02683cca75a5e785ff70d68274049 100644 --- a/arkguard/package.json +++ b/arkguard/package.json @@ -64,4 +64,4 @@ "README-cn.md", "Version.md" ] -} \ No newline at end of file +} diff --git a/ets2panda/aot/main.cpp b/ets2panda/aot/main.cpp index face618ccbbcf2bd1ccc1d567dfbebd1be7b9f0b..8400b0adda306f18bb6a2f18efce824f7844eb81 100644 --- a/ets2panda/aot/main.cpp +++ b/ets2panda/aot/main.cpp @@ -26,6 +26,7 @@ #include "util/plugin.h" #include "libpandabase/os/stacktrace.h" #include "generated/diagnostic.h" +#include "public/es2panda_lib.h" #include #include @@ -136,6 +137,7 @@ static int Run(Span args) if (!options->Parse(args)) { return 1; } + diagnosticEngine.SetWError(options->IsEtsWarningsWerror()); ark::Logger::ComponentMask mask {}; mask.set(ark::Logger::Component::ES2PANDA); @@ -173,8 +175,56 @@ static int Run(Span args) } } // namespace ark::es2panda::aot +void RunInParallel(std::string &fileName, es2panda_GlobalContext *globalCtx) +{ + // NOLINTNEXTLINE + const char *args[] = {"out/bin/es2panda", fileName.c_str(), + "--arktsconfig=/mnt/data/huyunhui/openharmony-ArkTS1.2/arkcompiler/ets_frontend/ets2panda/" + "driver/build_system/dist/cache/entry/arktsconfig.json"}; + auto impl = es2panda_GetImpl(1); + auto cfg = impl->CreateConfig(3, args); + auto ctx = impl->CreateCacheContextFromFile(cfg, fileName.c_str(), globalCtx, false); + impl->ProceedToState(ctx, ES2PANDA_STATE_LOWERED); + impl->DestroyConfig(cfg); + impl->DestroyContext(ctx); +} + int main(int argc, const char *argv[]) { + { + // auto g_Impl = es2panda_GetImpl((1)); + // + // g_Impl->MemInitialize(); + // auto cfg = g_Impl->CreateConfig(argc, argv); // 给stdlib生成cache使用 + // // const char *fileList[] = {"/mnt/data/huyunhui/ArkTS1.2/runtime_core/static_core/test.ets", + // // "/mnt/data/huyunhui/ArkTS1.2/runtime_core/static_core/test1.ets"}; + // auto globalCtx = g_Impl->CreateGlobalContext(cfg, {}, 0); + // + // // // 起worker + // // // cfg = g_Impl->CreateConfig(argc, argv) + // // // ctx = g_Impl->CreateCnntext(); + // + // // // 对同一文件 + // // // 对于external program + // // // ProceedToState(LOWERED) + // // // 对于main program + // // // ProceedToState(BIN_GENERATED) + // + // // // destroyConext + // // // destroyConfig + // { + // std::string file1 = "/mnt/data/huyunhui/ArkTS1.2/runtime_core/static_core/test.ets"; + // // std::string file2 = "/mnt/data/huyunhui/ArkTS1.2/runtime_core/static_core/test1.ets"; + // std::thread t1(RunInParallel, std::ref(file1), globalCtx); + // // std::thread t2(RunInParallel, std::ref(file2), globalCtx); + // t1.join(); + // // t2.join(); + // } + // + // g_Impl->DestroyGlobalContext(globalCtx); + // g_Impl->DestroyConfig(cfg); + // g_Impl->MemFinalize(); + } ark::es2panda::aot::MemManager mm; return ark::es2panda::aot::Run(ark::Span(argv, argc)); } diff --git a/ets2panda/checker/ASchecker.cpp b/ets2panda/checker/ASchecker.cpp index 3a3cb8e6919aafd41329ac9b4fa2d6880ee55fff..fc12aeeb658d14305ee0a13cc2221a91cabd25f2 100644 --- a/ets2panda/checker/ASchecker.cpp +++ b/ets2panda/checker/ASchecker.cpp @@ -21,8 +21,6 @@ namespace ark::es2panda::checker { bool ASChecker::StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const util::Options &options) { - Initialize(varbinder); - if (options.IsDumpAst()) { std::cout << Program()->Dump() << std::endl; } diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 30b38acdfb096695314afee82779c0adbcb3d823..6745971b6f465894edc700c517823bc82d76d292 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1621,7 +1621,7 @@ checker::Type *ETSAnalyzer::Check(ir::Identifier *expr) const } std::pair SearchReExportsType(ETSObjectType *baseType, ir::MemberExpression *expr, - util::StringView &aliasName, ETSChecker *checker) + util::StringView const &aliasName, ETSChecker *checker) { std::pair ret {}; @@ -1704,8 +1704,8 @@ checker::Type *ETSAnalyzer::Check(ir::MemberExpression *expr) const if (baseType->IsETSObjectType() && !baseType->AsETSObjectType()->ReExports().empty() && baseType->AsETSObjectType()->GetProperty(expr->Property()->AsIdentifier()->Name(), PropertySearchFlags::SEARCH_ALL) == nullptr) { - if (auto reExportType = SearchReExportsType(baseType->AsETSObjectType(), expr, - expr->Property()->AsIdentifier()->Name(), checker); + auto const &name = expr->Property()->AsIdentifier()->Name(); + if (auto reExportType = SearchReExportsType(baseType->AsETSObjectType(), expr, name, checker); reExportType.first != nullptr) { baseType = reExportType.first; expr->object_->AsIdentifier()->SetTsType(baseType); @@ -2292,10 +2292,9 @@ checker::Type *ETSAnalyzer::Check(ir::BlockStatement *st) const stmt->Check(checker); // NOTE! Processing of trailing blocks was moved here so that smart casts could be applied correctly - if (auto const tb = st->trailingBlocks_.find(stmt); tb != st->trailingBlocks_.end()) { - auto *const trailingBlock = tb->second; + if (auto *const trailingBlock = st->SearchStatementInTrailingBlock(stmt); trailingBlock != nullptr) { trailingBlock->Check(checker); - st->Statements().emplace(std::next(st->Statements().begin() + idx), trailingBlock); + st->AddStatement(idx, trailingBlock); ++idx; } } @@ -2631,7 +2630,8 @@ static bool CheckIsValidReturnTypeAnnotation(ir::ReturnStatement *st, ir::Script ir::TypeNode *returnTypeAnnotation, ETSChecker *checker) { // check valid `this` type as return type - if (containingFunc->GetPreferredReturnType() != nullptr || !returnTypeAnnotation->IsTSThisType()) { + if (containingFunc->GetPreferredReturnType() != nullptr || + (returnTypeAnnotation != nullptr && !returnTypeAnnotation->IsTSThisType())) { return true; } diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index 24b38be959d852698d06721db05a4e06faa36b93..6d28eeb0e97924c24113a681bbaa076b08f7c930 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -31,6 +31,9 @@ #include "util/helpers.h" #include "evaluate/scopedDebugInfoPlugin.h" +#include +#include + namespace ark::es2panda::checker { static util::StringView InitBuiltin(ETSChecker *checker, std::string_view signature) @@ -52,7 +55,7 @@ static util::StringView InitBuiltin(ETSChecker *checker, std::string_view signat void ETSChecker::CheckObjectLiteralKeys(const ArenaVector &properties) { - static std::set names; + thread_local static std::set names; names.clear(); for (auto property : properties) { @@ -253,15 +256,119 @@ void ETSChecker::InitializeBuiltin(varbinder::Variable *var, const util::StringV GetGlobalTypesHolder()->InitializeBuiltin(name, type); } -bool ETSChecker::StartChecker(varbinder::VarBinder *varbinder, const util::Options &options) +void ETSChecker::ReputAbsturctClass(std::string_view name) +{ + return; + std::function calcuAbsturctClassRecursive = [&](ETSObjectType *classType) { + if (auto it = calculatedClass_.find(classType); it != calculatedClass_.end()) { + return; + } + calculatedClass_.insert(classType); + if (classType->SuperType() != nullptr) { + calcuAbsturctClassRecursive(classType->SuperType()); + } + GetAbstractsForClass(classType); + }; + // Replace Record Object Expressions with Block Expressions + for (auto &[_, extPrograms] : Program()->ExternalSources()) { + (void)_; + for (auto *extProg : extPrograms) { + if (!extProg->IsASTLowered()) { + return; + } + extProg->Ast()->TransformChildrenRecursively( + // CC-OFFNXT(G.FMT.14-CPP) project code style + [&](ir::AstNode *ast) -> ir::AstNode * { + if (ast->IsClassDefinition() && ((ast->Modifiers() & ir::ModifierFlags::FUNCTIONAL) == 0)) { + calcuAbsturctClassRecursive(ast->AsClassDefinition()->TsType()->AsETSObjectType()); + } + return ast; + }, + name); + } + } +} + +void ETSChecker::ReputExtensionAccessorCache(std::string_view name) { - Initialize(varbinder); + for (auto &[_, extPrograms] : Program()->ExternalSources()) { + (void)_; + for (auto *extProg : extPrograms) { + extProg->Ast()->TransformChildrenRecursively( + // CC-OFFNXT(G.FMT.14-CPP) project code style + [&](ir::AstNode *ast) -> ir::AstNode * { + if (ast->IsCallExpression() && ast->AsCallExpression()->Signature() != nullptr && + ast->AsCallExpression()->Signature()->HasSignatureFlag(SignatureFlags::EXTENSION_FUNCTION)) { + std::cout << "xsx" << std::endl; + } + return ast; + }, + name); + } + } +} +void ETSChecker::ReputPartialTypeClass() +{ + for (auto &[_, extPrograms] : Program()->ExternalSources()) { + (void)_; + for (auto *extProg : extPrograms) { + auto extRecord = VarBinder()->AsETSBinder()->GetExternalRecordTable().at(extProg); + extProg->Ast()->IterateRecursively( + // CC-OFFNXT(G.FMT.14-CPP) project code style + [&](ir::AstNode *ast) -> void { + if (ast->IsClassDefinition()) { + varbinder::BoundContext(extRecord, ast->AsClassDefinition()); + } else if (ast->IsAnnotationDeclaration()) { + varbinder::BoundContext(extRecord, ast->AsAnnotationDeclaration()); + } else if (ast->IsTSInterfaceDeclaration()) { + varbinder::BoundContext(extRecord, ast->AsTSInterfaceDeclaration()); + } + }); + } + } +} + +void ETSChecker::ReputCheckerData() +{ + // auto name = std::string_view("ReputCheckerData"); + ArenaSet readdedChecker(Allocator()->Adapter()); + for (auto &[_, extPrograms] : Program()->ExternalSources()) { + (void)_; + auto *extProg = extPrograms.front(); + if (!extProg->IsASTLowered()) { + continue; + } + auto eChecker = extProg->Checker()->AsETSChecker(); + SetGlobalTypesHolder(eChecker->GetGlobalTypesHolder()); + AddStatus(CheckerStatus::BUILTINS_INITIALIZED); + if (auto it = readdedChecker.find(eChecker); it != readdedChecker.end()) { + return; + } + readdedChecker.insert(eChecker); + auto &computedAbstractMapToCopy = eChecker->cachedComputedAbstracts_; + for (auto &[key, value] : computedAbstractMapToCopy) { + auto &[v1, v2] = value; + ArenaVector newV1(Allocator()->Adapter()); + ArenaUnorderedSet newV2(Allocator()->Adapter()); + newV1.assign(v1.cbegin(), v1.cend()); + newV2.insert(v2.cbegin(), v2.cend()); + cachedComputedAbstracts_.try_emplace(key, newV1, newV2); + } + + auto &globalArraySigs = eChecker->globalArraySignatures_; + globalArraySignatures_.insert(globalArraySigs.begin(), globalArraySigs.end()); + } +} + +bool ETSChecker::StartChecker(varbinder::VarBinder *varbinder, const util::Options &options) +{ if (options.IsParseOnly()) { return false; } auto *etsBinder = varbinder->AsETSBinder(); + InitializeBuiltins(etsBinder); for (auto &entry : etsBinder->DynamicImportVars()) { @@ -290,7 +397,9 @@ bool ETSChecker::StartChecker(varbinder::VarBinder *varbinder, const util::Optio } #endif - if (options.IsDumpDynamicAst()) { + static bool ekko = true; + if (options.IsDumpDynamicAst() && ekko) { + ekko = false; std::cout << Program()->Dump() << std::endl; } @@ -322,9 +431,13 @@ void ETSChecker::CheckProgram(parser::Program *program, bool runAnalysis) for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { - checker::SavedCheckerContext savedContext(this, Context().Status(), Context().ContainingClass()); - AddStatus(checker::CheckerStatus::IN_EXTERNAL); - CheckProgram(extProg, VarBinder()->IsGenStdLib()); + if (!extProg->IsASTLowered()) { + extProg->PushChecker(this); + varbinder::RecordTableContext recordTableCtx(VarBinder()->AsETSBinder(), extProg); + checker::SavedCheckerContext savedContext(this, Context().Status(), Context().ContainingClass()); + AddStatus(checker::CheckerStatus::IN_EXTERNAL); + CheckProgram(extProg, VarBinder()->IsGenStdLib()); + } } } @@ -453,13 +566,13 @@ ETSObjectType *ETSChecker::GlobalETSObjectType() const ETSUnionType *ETSChecker::GlobalETSNullishType() const { - auto *ret = (GetGlobalTypesHolder()->*&GlobalTypesHolder::GlobalETSNullishType)(); + auto *ret = (GetGlobalTypesHolder()->GlobalETSNullishType)(); return ret != nullptr ? ret->AsETSUnionType() : nullptr; } ETSUnionType *ETSChecker::GlobalETSNullishObjectType() const { - auto *ret = (GetGlobalTypesHolder()->*&GlobalTypesHolder::GlobalETSNullishObjectType)(); + auto *ret = GetGlobalTypesHolder()->GlobalETSNullishObjectType(); return ret != nullptr ? ret->AsETSUnionType() : nullptr; } diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 5ee7f16b913e9bc0d495b7f141c223c586fdf238..9f27034398192ca0c4828630a9893ab98f33f7bb 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -178,6 +178,10 @@ public: Type *GuaranteedTypeForUncheckedCallReturn(Signature *sig); Type *GuaranteedTypeForUncheckedPropertyAccess(varbinder::Variable *prop); Type *GuaranteedTypeForUnionFieldAccess(ir::MemberExpression *memberExpression, ETSUnionType *etsUnionType); + void ReputCheckerData(); + void ReputAbsturctClass(std::string_view name); + void ReputExtensionAccessorCache(std::string_view name); + void ReputPartialTypeClass(); [[nodiscard]] bool IsETSChecker() const noexcept override { @@ -1032,6 +1036,7 @@ private: evaluate::ScopedDebugInfoPlugin *debugInfoPlugin_ {nullptr}; std::unordered_set elementStack_; ArenaVector overloadSigContainer_; + std::set calculatedClass_; }; } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/JSchecker.cpp b/ets2panda/checker/JSchecker.cpp index 3efe6f5b8d7bbc0d6d74297acdd42fcab796c441..62c02cc2064b2540fbdcc5551816e2681d53fa0f 100644 --- a/ets2panda/checker/JSchecker.cpp +++ b/ets2panda/checker/JSchecker.cpp @@ -23,7 +23,6 @@ namespace ark::es2panda::checker { bool JSChecker::StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const util::Options &options) { - Initialize(varbinder); varbinder->IdentifierAnalysis(); if (options.IsDumpAst()) { diff --git a/ets2panda/checker/TSchecker.cpp b/ets2panda/checker/TSchecker.cpp index 9e820dfc4d067f98c1dfe1c36f675edcd0e9ed44..4fe4acde5426a0b21f5bd43b23d7fb79f17e0d44 100644 --- a/ets2panda/checker/TSchecker.cpp +++ b/ets2panda/checker/TSchecker.cpp @@ -23,7 +23,6 @@ namespace ark::es2panda::checker { bool TSChecker::StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const util::Options &options) { - Initialize(varbinder); varbinder->IdentifierAnalysis(); if (options.IsDumpAst()) { diff --git a/ets2panda/checker/checker.cpp b/ets2panda/checker/checker.cpp index 625d98ecaec5b60e864c61707fe26d74e3c0e018..54247ff64389335c8396eb522704c0e3995ae84c 100644 --- a/ets2panda/checker/checker.cpp +++ b/ets2panda/checker/checker.cpp @@ -176,8 +176,10 @@ ScopeContext::ScopeContext(Checker *checker, varbinder::Scope *newScope) void Checker::CleanUp() { + if (!program_->IsASTLowered()) { + globalTypes_ = allocator_.New(&allocator_); + } context_ = CheckerContext(this, CheckerStatus::NO_OPTS); - globalTypes_ = allocator_.New(&allocator_); relation_ = allocator_.New(this); identicalResults_.cached.clear(); assignableResults_.cached.clear(); diff --git a/ets2panda/checker/checker.h b/ets2panda/checker/checker.h index 01d147ac9cc1777f71bdb90032e0d291bb60361c..dcd0ae8636b86d9b0428f8d0f5c30f38a09c72b2 100644 --- a/ets2panda/checker/checker.h +++ b/ets2panda/checker/checker.h @@ -49,6 +49,7 @@ namespace ark::es2panda::checker { class ETSChecker; class InterfaceType; class GlobalTypesHolder; +class SemanticAnalyzer; using StringLiteralPool = std::unordered_map; using NumberLiteralPool = std::unordered_map; @@ -68,7 +69,7 @@ public: NO_COPY_SEMANTIC(Checker); NO_MOVE_SEMANTIC(Checker); - [[nodiscard]] ArenaAllocator *Allocator() noexcept + [[nodiscard]] ThreadSafeArenaAllocator *Allocator() noexcept { return &allocator_; } @@ -108,6 +109,11 @@ public: return globalTypes_; } + void SetGlobalTypesHolder(GlobalTypesHolder *globalTypes) + { + globalTypes_ = globalTypes; + } + [[nodiscard]] RelationHolder &IdenticalResults() noexcept { return identicalResults_; @@ -226,7 +232,7 @@ protected: void SetProgram(parser::Program *program); private: - ArenaAllocator allocator_; + ThreadSafeArenaAllocator allocator_; CheckerContext context_; GlobalTypesHolder *globalTypes_; TypeRelation *relation_; diff --git a/ets2panda/checker/ets/dynamic.cpp b/ets2panda/checker/ets/dynamic.cpp index 503cb2567ebd0d96dc82c3a7e7c23919ee8ff76b..08ebc4d8409b2860a1600b65f87ce9b6ccc9415e 100644 --- a/ets2panda/checker/ets/dynamic.cpp +++ b/ets2panda/checker/ets/dynamic.cpp @@ -360,10 +360,14 @@ ir::ClassDeclaration *ETSChecker::BuildClass(util::StringView name, const ClassB // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *classDecl = AllocNode(classDef, Allocator()); - VarBinder()->Program()->Ast()->Statements().push_back(classDecl); + VarBinder()->Program()->Ast()->AddStatement(classDecl); classDecl->SetParent(VarBinder()->Program()->Ast()); - varbinder::BoundContext boundCtx(VarBinder()->AsETSBinder()->GetGlobalRecordTable(), classDef); + auto varBinder = VarBinder()->AsETSBinder(); + bool isExternal = VarBinder()->Program() != varBinder->GetGlobalRecordTable()->Program(); + auto recordTable = isExternal ? varBinder->GetExternalRecordTable().at(varBinder->Program()) + : VarBinder()->AsETSBinder()->GetGlobalRecordTable(); + varbinder::BoundContext boundCtx(recordTable, classDef); ArenaVector classBody(Allocator()->Adapter()); @@ -577,7 +581,7 @@ void ETSChecker::EmitDynamicModuleClassInitCall() // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *const node = AllocNode(initCall); node->SetParent(cctorBody); - cctorBody->Statements().push_back(node); + cctorBody->AddStatement(node); ProcessScopesNode(this, node); ProcessCheckerNode(this, node); @@ -600,7 +604,7 @@ void ETSChecker::BuildClassBodyFromDynamicImports(const ArenaVectorAssemblerName() = util::UString(assemblyName, Allocator()).View(); + import->SetAssemblerName(util::UString(assemblyName, Allocator()).View()); fields.insert(import->AssemblerName()); imports.push_back(import); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 4b4ba3f40a522fd62a9016e80b52b21d05c467a8..aeaabe19e01f573e5c28578f0424df3c7271dbe9 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -1206,11 +1206,16 @@ static bool CollectOverload(checker::ETSChecker *checker, ir::MethodDefinition * method->Id()->Variable()->SetTsType(checker->GlobalTypeError()); return false; } - auto *const overloadType = checker->BuildMethodType(currentFunc->Function()); + + auto *const overloadType = currentFunc->TsType() != nullptr ? currentFunc->TsType()->AsETSFunctionType() + : checker->BuildMethodType(currentFunc->Function()); ldInfo.needHelperOverload |= checker->CheckIdenticalOverloads(funcType, overloadType, currentFunc, ldInfo.isDeclare); - currentFunc->SetTsType(overloadType); + if (currentFunc->TsType() == nullptr) { + currentFunc->SetTsType(overloadType); + } + auto overloadSig = currentFunc->Function()->Signature(); funcType->AddCallSignature(overloadSig); if (overloadSig->IsExtensionAccessor()) { @@ -1446,6 +1451,10 @@ void ETSChecker::ValidateMainSignature(ir::ScriptFunction *func) void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig) { bool isArrow = func->IsArrow(); + // note(Ekko): For extenal function overload, need to not change ast tree, for arrow type, need perferred type. + if (func->Signature() != nullptr && !isArrow) { + return; + } auto *nameVar = isArrow ? nullptr : func->Id()->Variable(); auto funcName = nameVar == nullptr ? util::StringView() : nameVar->Name(); @@ -1453,6 +1462,7 @@ void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstru auto thisVar = func->Scope()->ParamScope()->Params().front(); thisVar->SetTsType(Context().ContainingClass()); } + auto *signatureInfo = ComposeSignatureInfo(func->TypeParams(), func->Params()); auto *returnType = func->GetPreferredReturnType() != nullptr ? func->GetPreferredReturnType() @@ -1478,7 +1488,6 @@ void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstru if (func->IsEntryPoint()) { ValidateMainSignature(func); } - VarBinder()->AsETSBinder()->BuildFunctionName(func); } diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index cb412ffb619d38c1a2a5cc1e175fdf8122ba5fa5..0d75a54c6c5fa5de3bb5b6091a77d2b3d5b39c22 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1649,6 +1649,9 @@ void ETSChecker::BindingsModuleObjectAddProperty(checker::ETSObjectType *moduleO for (auto [_, var] : bindings) { (void)_; auto [found, aliasedName] = FindSpecifierForModuleObject(importDecl, var->AsLocalVariable()->Name()); + if (!var->AsLocalVariable()->Declaration()->Node()->IsValidInCurrentPhase()) { + continue; + } if ((var->AsLocalVariable()->Declaration()->Node()->IsExported() || var->AsLocalVariable()->Declaration()->Node()->IsExportedType()) && found) { diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index 6a3936e8037339611e5f2e0de6ce8b4cb6ffba83..20d544f0a4d991909e2313efeb628dd8ae05bba8 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -1092,7 +1092,7 @@ void ETSChecker::MaybeReportErrorsForOverridingValidation(ArenaVectorHasObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS)) { + if (auto it = cachedComputedAbstracts_.find(classType);it!=cachedComputedAbstracts_.end()) { return; } @@ -1125,7 +1125,6 @@ void ETSChecker::ValidateOverriding(ETSObjectType *classType, const lexer::Sourc ValidateAbstractMethodsToBeImplemented(abstractsToBeImplemented, classType, implementedSignatures); MaybeReportErrorsForOverridingValidation(abstractsToBeImplemented, classType, pos, throwError); - classType->AddObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS); } void ETSChecker::AddImplementedSignature(std::vector *implementedSignatures, diff --git a/ets2panda/checker/ets/typeRelationContext.cpp b/ets2panda/checker/ets/typeRelationContext.cpp index 00dcde0ae4f6226f2eee1d2649cfaf76282d2fd1..f8a63c3124d2491566597e6e17444b8c26872b8a 100644 --- a/ets2panda/checker/ets/typeRelationContext.cpp +++ b/ets2panda/checker/ets/typeRelationContext.cpp @@ -179,7 +179,7 @@ void InstantiationContext::InstantiateType(ETSObjectType *type, ArenaVectorSubstitute(checker_->Relation(), substitution)->AsETSObjectType(); - type->GetInstantiationMap().try_emplace(hash, result_->AsETSObjectType()); + type->InsertInstantiationMap(hash, result_->AsETSObjectType()); result_->AddTypeFlag(TypeFlag::GENERIC); ctScope.TryCheckConstraints(); diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp index 69ed5cb22c569d29fc1d81fd55c2e6f5b4ef0351..6a69f15cdec19159e95c5762ca1cfffbf20fafc4 100644 --- a/ets2panda/checker/ets/utilityTypeHandlers.cpp +++ b/ets2panda/checker/ets/utilityTypeHandlers.cpp @@ -98,7 +98,7 @@ static std::pair GetPartialClassPro ir::AstNode *typeNode) { auto classDefProgram = typeNode->GetTopStatement()->AsETSModule()->Program(); - if (classDefProgram == checker->VarBinder()->Program()) { + if (classDefProgram == checker->VarBinder()->AsETSBinder()->GetGlobalRecordTable()->Program()) { return {classDefProgram, checker->VarBinder()->AsETSBinder()->GetGlobalRecordTable()}; } return {classDefProgram, checker->VarBinder()->AsETSBinder()->GetExternalRecordTable().at(classDefProgram)}; @@ -205,7 +205,11 @@ Type *ETSChecker::HandlePartialInterface(ir::TSInterfaceDeclaration *interfaceDe } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + // to be refactored + auto savedScope = VarBinder()->TopScope(); + VarBinder()->ResetTopScope(partialProgram->GlobalScope()); auto *partialType = CreatePartialTypeInterfaceDecl(interfaceDecl, typeToBePartial, partialInterDecl); + VarBinder()->ResetTopScope(savedScope); ES2PANDA_ASSERT(partialType != nullptr); NamedTypeStackElement ntse(this, partialType); @@ -591,10 +595,11 @@ ir::TSInterfaceDeclaration *ETSChecker::CreateInterfaceProto(util::StringView na // Put class declaration in global scope, and in program AST partialInterface->SetParent(interfaceDeclProgram->Ast()); - interfaceDeclProgram->Ast()->Statements().push_back(partialInterface); + interfaceDeclProgram->Ast()->AddStatement(partialInterface); interfaceDeclProgram->GlobalScope()->InsertBinding(name, var); partialInterface->AddModifier(flags); + partialInterface->ClearModifier(ir::ModifierFlags::EXPORTED); return partialInterface; } @@ -667,7 +672,9 @@ Type *ETSChecker::CreatePartialTypeInterfaceDecl(ir::TSInterfaceDeclaration *con partialInterface->TypeParams()); } - compiler::InitScopesPhaseETS::RunExternalNode(partialInterface, VarBinder()); + { + compiler::InitScopesPhaseETS::RunExternalNode(partialInterface, VarBinder()); + } auto methodscope = partialInterface->Scope()->AsClassScope()->InstanceMethodScope(); // Add getter methods to instancemethodscope. @@ -764,7 +771,7 @@ ir::ClassDefinition *ETSChecker::CreateClassPrototype(util::StringView name, par decl->BindNode(classDef); // Put class declaration in global scope, and in program AST - classDeclProgram->Ast()->Statements().push_back(classDecl); + classDeclProgram->Ast()->AddStatement(classDecl); classDeclProgram->GlobalScope()->InsertBinding(name, var); return classDef; @@ -953,7 +960,7 @@ Type *ETSChecker::GetReadonlyType(Type *type) void ETSChecker::MakePropertiesReadonly(ETSObjectType *const classType) { - classType->UpdateTypeProperties(this, [this](auto *property, auto *propType) { + classType->UpdateTypeProperties([this](auto *property, auto *propType) { auto *newDecl = Allocator()->New(property->Name(), property->Declaration()->Node()); auto *const propCopy = property->Copy(Allocator(), newDecl); propCopy->AddFlag(varbinder::VariableFlags::READONLY); diff --git a/ets2panda/checker/types/ets/etsAsyncFuncReturnType.h b/ets2panda/checker/types/ets/etsAsyncFuncReturnType.h index e1ede4842b6fe35b3dc6ac4d712bf8e26ed064f2..e079ff71a6802e5d9e84768e4484c6288bc40fce 100644 --- a/ets2panda/checker/types/ets/etsAsyncFuncReturnType.h +++ b/ets2panda/checker/types/ets/etsAsyncFuncReturnType.h @@ -23,7 +23,7 @@ class GlobalTypesHolder; class ETSAsyncFuncReturnType : public ETSObjectType { public: - ETSAsyncFuncReturnType(ArenaAllocator *allocator, TypeRelation *relation, ETSObjectType *promiseType) + ETSAsyncFuncReturnType(ThreadSafeArenaAllocator *allocator, TypeRelation *relation, ETSObjectType *promiseType) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_OBJECT, std::make_tuple(nullptr, ETSObjectFlags::ASYNC_FUNC_RETURN_TYPE, relation)), promiseType_(promiseType) diff --git a/ets2panda/checker/types/ets/etsBigIntType.h b/ets2panda/checker/types/ets/etsBigIntType.h index 279c5d08170a65b67037458472b7d959bcc61005..8ed5f40ccb1f3ecdda34f88f5fdc60eee0483297 100644 --- a/ets2panda/checker/types/ets/etsBigIntType.h +++ b/ets2panda/checker/types/ets/etsBigIntType.h @@ -21,14 +21,14 @@ namespace ark::es2panda::checker { class ETSBigIntType : public ETSObjectType { public: - explicit ETSBigIntType(ArenaAllocator *allocator, [[maybe_unused]] ETSObjectType *super) + explicit ETSBigIntType(ThreadSafeArenaAllocator *allocator, [[maybe_unused]] ETSObjectType *super) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_BIGINT, nullptr, ETSObjectFlags::CLASS | ETSObjectFlags::BUILTIN_BIGINT | ETSObjectFlags::RESOLVED_SUPER) { SetSuperType(super); } - explicit ETSBigIntType(ArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, + explicit ETSBigIntType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, util::StringView value) : ETSObjectType( allocator, "", compiler::Signatures::BUILTIN_BIGINT, diff --git a/ets2panda/checker/types/ets/etsDynamicType.h b/ets2panda/checker/types/ets/etsDynamicType.h index eea79b4fb92a6ea1b1275bdfc17aa8c1a845ad9c..5dcf86392602d5f1d4b7ff6bcf78f4d3db20744d 100644 --- a/ets2panda/checker/types/ets/etsDynamicType.h +++ b/ets2panda/checker/types/ets/etsDynamicType.h @@ -28,7 +28,7 @@ class ETSDynamicType : public ETSObjectType { static constexpr auto RELATION = 2; public: - explicit ETSDynamicType(ArenaAllocator *allocator, std::tuple label, + explicit ETSDynamicType(ThreadSafeArenaAllocator *allocator, std::tuple label, std::tuple info, bool hasDecl) : ETSObjectType(allocator, std::get(label), std::get(label), std::make_tuple(std::get(info), std::get(info) | ETSObjectFlags::DYNAMIC, diff --git a/ets2panda/checker/types/ets/etsEnumType.h b/ets2panda/checker/types/ets/etsEnumType.h index a5c6bdf33d7a3e767413365b6105f75f9114285b..a5019aa62ceacdb1fd62c6fc027cf61117064090 100644 --- a/ets2panda/checker/types/ets/etsEnumType.h +++ b/ets2panda/checker/types/ets/etsEnumType.h @@ -24,7 +24,7 @@ namespace ark::es2panda::checker { class ETSEnumType : public ETSObjectType { public: - explicit ETSEnumType(ArenaAllocator *allocator, util::StringView name, util::StringView internalName, + explicit ETSEnumType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView internalName, ir::AstNode *declNode, TypeRelation *relation) : ETSObjectType(allocator, name, internalName, std::make_tuple(declNode, ETSObjectFlags::CLASS | ETSObjectFlags::ENUM_OBJECT, relation)) @@ -49,7 +49,7 @@ public: class ETSIntEnumType : public ETSEnumType { public: - explicit ETSIntEnumType(ArenaAllocator *allocator, util::StringView name, util::StringView internalName, + explicit ETSIntEnumType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView internalName, ir::AstNode *declNode, TypeRelation *relation) : ETSEnumType(allocator, name, internalName, declNode, relation) { @@ -70,7 +70,7 @@ public: class ETSStringEnumType : public ETSEnumType { public: - explicit ETSStringEnumType(ArenaAllocator *allocator, util::StringView name, util::StringView internalName, + explicit ETSStringEnumType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView internalName, ir::AstNode *declNode, TypeRelation *relation) : ETSEnumType(allocator, name, internalName, declNode, relation) { diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index 5d54c7235bfa01c6cc5825a3c67e5ef2436ad080..03a56172da0c1f5649c0f01bb88cba12b1faf97f 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -18,6 +18,10 @@ #include "checker/ETSchecker.h" #include "checker/ets/conversion.h" #include "checker/types/globalTypesHolder.h" +#include "ir/statements/annotationDeclaration.h" +#include "checker/types/ets/etsAsyncFuncReturnType.h" +#include "checker/types/ets/etsEnumType.h" +#include "checker/types/ets/etsDynamicFunctionType.h" namespace ark::es2panda::checker { @@ -855,6 +859,7 @@ void ETSObjectType::IsGenericSupertypeOf(TypeRelation *relation, ETSObjectType * Type *ETSObjectType::AsSuper(Checker *checker, varbinder::Variable *sourceVar) { + checker = GetETSChecker(); if (sourceVar == nullptr) { return nullptr; } @@ -1041,13 +1046,14 @@ void ETSObjectType::SetCopiedTypeProperties(TypeRelation *const relation, ETSObj copiedType->effectiveSubstitution_ = ComputeEffectiveSubstitution(relation, baseTypeParams, newTypeArgs); copiedType->SetTypeArguments(std::move(newTypeArgs)); + ASSERT(relation); copiedType->relation_ = relation; } -void ETSObjectType::UpdateTypeProperty(checker::ETSChecker *checker, varbinder::LocalVariable *const prop, - PropertyType fieldType, PropertyProcesser const &func) +void ETSObjectType::UpdateTypeProperty(varbinder::LocalVariable *const prop, PropertyType fieldType, + PropertyProcesser const &func) { - auto const propType = prop->Declaration()->Node()->Check(checker); + auto const propType = prop->Declaration()->Node()->Check(GetETSChecker()); auto *const propCopy = func(prop, propType); if (fieldType == PropertyType::INSTANCE_FIELD) { @@ -1059,24 +1065,116 @@ void ETSObjectType::UpdateTypeProperty(checker::ETSChecker *checker, varbinder:: } } -void ETSObjectType::UpdateTypeProperties(checker::ETSChecker *checker, PropertyProcesser const &func) +void ETSObjectType::UpdateTypeProperties(PropertyProcesser const &func) { AddTypeFlag(TypeFlag::READONLY); for (auto const &prop : InstanceFields()) { - UpdateTypeProperty(checker, prop.second, PropertyType::INSTANCE_FIELD, func); + UpdateTypeProperty(prop.second, PropertyType::INSTANCE_FIELD, func); } for (auto const &prop : StaticFields()) { - UpdateTypeProperty(checker, prop.second, PropertyType::STATIC_FIELD, func); + UpdateTypeProperty(prop.second, PropertyType::STATIC_FIELD, func); } if (SuperType() != nullptr) { - auto *const superProp = SuperType()->Clone(checker)->AsETSObjectType(); - superProp->UpdateTypeProperties(checker, func); + auto *const superProp = + SuperType() + ->Instantiate(allocator_, relation_, relation_->GetChecker()->GetGlobalTypesHolder()) + ->AsETSObjectType(); + superProp->UpdateTypeProperties(func); SetSuperType(superProp); } } +static util::StringView GetHashFromSubstitution(const Substitution *substitution, const bool extensionFuncFlag, + ArenaAllocator *allocator) +{ + std::vector fields; + for (auto [k, v] : *substitution) { + std::stringstream ss; + k->ToString(ss, true); + ss << ":"; + v->ToString(ss, true); + // NOTE (mmartin): change bare address to something more appropriate unique representation + ss << ":" << k << ":" << v; + fields.push_back(ss.str()); + } + std::sort(fields.begin(), fields.end()); + + std::stringstream ss; + for (auto &fstr : fields) { + ss << fstr; + ss << ";"; + } + + if (extensionFuncFlag) { + ss << "extensionFunctionType;"; + } + return util::UString(ss.str(), allocator).View(); +} + +static std::pair GetObjectTypeDeclNames(ir::AstNode *node) +{ + if (node->IsClassDefinition()) { + return {node->AsClassDefinition()->Ident()->Name(), node->AsClassDefinition()->InternalName()}; + } + if (node->IsTSInterfaceDeclaration()) { + return {node->AsTSInterfaceDeclaration()->Id()->Name(), node->AsTSInterfaceDeclaration()->InternalName()}; + } + return {node->AsAnnotationDeclaration()->GetBaseName()->Name(), node->AsAnnotationDeclaration()->InternalName()}; +} + +static std::tuple CheckForDynamicLang(ir::AstNode *declNode, util::StringView assemblerName) +{ + Language lang(Language::Id::ETS); + bool hasDecl = false; + + if (declNode->IsClassDefinition()) { + auto *clsDef = declNode->AsClassDefinition(); + lang = clsDef->Language(); + hasDecl = clsDef->IsDeclare(); + } + + if (declNode->IsTSInterfaceDeclaration()) { + auto *ifaceDecl = declNode->AsTSInterfaceDeclaration(); + lang = ifaceDecl->Language(); + hasDecl = ifaceDecl->IsDeclare(); + } + + auto res = compiler::Signatures::Dynamic::LanguageFromType(assemblerName.Utf8()); + if (res) { + lang = *res; + } + + return std::make_tuple(lang, hasDecl); +} + +ETSObjectType *ETSObjectType::CreateETSObjectType(ir::AstNode *declNode, ETSObjectFlags flags) +{ + auto const [name, internalName] = GetObjectTypeDeclNames(declNode); + + if (declNode->IsClassDefinition() && (declNode->AsClassDefinition()->IsEnumTransformed())) { + if (declNode->AsClassDefinition()->IsIntEnumTransformed()) { + return Allocator()->New(Allocator(), name, internalName, declNode, GetRelation()); + } + ES2PANDA_ASSERT(declNode->AsClassDefinition()->IsStringEnumTransformed()); + return Allocator()->New(Allocator(), name, internalName, declNode, GetRelation()); + } + + if (auto [lang, hasDecl] = CheckForDynamicLang(declNode, internalName); lang.IsDynamic()) { + return Allocator()->New(Allocator(), std::make_tuple(name, internalName, lang), + std::make_tuple(declNode, flags, GetRelation()), hasDecl); + } + + if (internalName == compiler::Signatures::BUILTIN_ARRAY) { + return Allocator()->New(Allocator(), name, + std::make_tuple(declNode, flags, GetRelation())); + } + + return Allocator()->New(Allocator(), name, internalName, + std::make_tuple(declNode, flags, GetRelation())); +} + // #22951: remove isExtensionFunctionType flag ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitution *substitution, bool cache, bool isExtensionFunctionType) @@ -1085,10 +1183,9 @@ ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitut return this; } - auto *const checker = relation->GetChecker()->AsETSChecker(); auto *base = GetOriginalBaseType(); - ArenaVector newTypeArgs {checker->Allocator()->Adapter()}; + ArenaVector newTypeArgs {allocator_->Adapter()}; const bool anyChange = SubstituteTypeArgs(relation, newTypeArgs, substitution); // Lambda types can capture type params in their bodies, normal classes cannot. // NOTE: gogabr. determine precise conditions where we do not need to copy. @@ -1097,7 +1194,7 @@ ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitut return this; } - const util::StringView hash = checker->GetHashFromSubstitution(substitution, isExtensionFunctionType); + const util::StringView hash = GetHashFromSubstitution(substitution, isExtensionFunctionType, allocator_); if (cache) { if (auto *inst = GetInstantiatedType(hash); inst != nullptr) { return inst; @@ -1109,14 +1206,15 @@ ETSObjectType *ETSObjectType::Substitute(TypeRelation *relation, const Substitut } relation->IncreaseTypeRecursionCount(base); - auto *const copiedType = checker->CreateETSObjectType(declNode_, flags_); + auto *const copiedType = CreateETSObjectType(declNode_, flags_); SetCopiedTypeProperties(relation, copiedType, std::move(newTypeArgs), base); if (isExtensionFunctionType) { copiedType->AddObjectFlag(checker::ETSObjectFlags::EXTENSION_FUNCTION); } if (cache) { - GetInstantiationMap().try_emplace(hash, copiedType); + ASSERT(copiedType->GetRelation()); + InsertInstantiationMap(hash, copiedType); } if (superType_ != nullptr) { @@ -1156,6 +1254,11 @@ ETSObjectType *ETSObjectType::SubstituteArguments(TypeRelation *relation, ArenaV return Substitute(relation, substitution); } +ETSChecker *ETSObjectType::GetETSChecker() +{ + return relation_->GetChecker()->AsETSChecker(); +} + void ETSObjectType::InstantiateProperties() const { ES2PANDA_ASSERT(relation_ != nullptr); diff --git a/ets2panda/checker/types/ets/etsObjectType.h b/ets2panda/checker/types/ets/etsObjectType.h index 9a174689dd7925c03ca8557b5caf2c2a044d2338..4800b6999e2563c1065828ad6408210ec9ff4621 100644 --- a/ets2panda/checker/types/ets/etsObjectType.h +++ b/ets2panda/checker/types/ets/etsObjectType.h @@ -24,6 +24,11 @@ #include "ir/ts/tsEnumDeclaration.h" #include "varbinder/scope.h" #include "ir/base/classDefinition.h" +#include "checker/checker.h" + +#include +#include +#include namespace ark::es2panda::checker { using PropertyProcesser = std::function; @@ -37,14 +42,14 @@ public: using PropertyTraverser = std::function; using PropertyHolder = std::array(PropertyType::COUNT)>; - explicit ETSObjectType(ArenaAllocator *allocator, util::StringView name, util::StringView internalName, + explicit ETSObjectType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView internalName, ir::AstNode *declNode, ETSObjectFlags flags) : ETSObjectType(allocator, name, internalName, std::make_tuple(declNode, flags, nullptr), std::make_index_sequence(PropertyType::COUNT)> {}) { } - explicit ETSObjectType(ArenaAllocator *allocator, util::StringView name, util::StringView internalName, + explicit ETSObjectType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView internalName, std::tuple info) : ETSObjectType(allocator, name, internalName, info, std::make_index_sequence(PropertyType::COUNT)> {}) @@ -70,6 +75,8 @@ public: } } + ETSChecker *GetETSChecker(); + void SetSuperType(ETSObjectType *super) { superType_ = super; @@ -92,6 +99,7 @@ public: void SetRelation(TypeRelation *relation) { + ASSERT(relation); relation_ = relation; } @@ -158,7 +166,7 @@ public: return interfaces_; } - ArenaVector &Interfaces() + const ArenaVector &Interfaces() { return interfaces_; } @@ -278,6 +286,7 @@ public: ETSObjectType *GetInstantiatedType(util::StringView hash) { + std::shared_lock lock(instantiationMapMutex_); auto found = instantiationMap_.find(hash); if (found != instantiationMap_.end()) { return found->second; @@ -295,9 +304,10 @@ public: return typeParams->Scope(); } - InstantiationMap &GetInstantiationMap() + auto InsertInstantiationMap(const util::StringView &key, ETSObjectType *value) { - return instantiationMap_; + std::unique_lock lock(instantiationMapMutex_); + return instantiationMap_.try_emplace(key, value); } template @@ -361,7 +371,7 @@ public: const util::StringView &name, PropertySearchFlags flags) 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; @@ -369,7 +379,7 @@ public: void AssignmentTarget(TypeRelation *relation, Type *source) override; bool IsBoxedPrimitive() const; Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; - void UpdateTypeProperties(checker::ETSChecker *checker, PropertyProcesser const &func); + void UpdateTypeProperties(PropertyProcesser const &func); ETSObjectType *Substitute(TypeRelation *relation, const Substitution *substitution) override; ETSObjectType *Substitute(TypeRelation *relation, const Substitution *substitution, bool cache, bool isExtensionFunctionType = false); @@ -378,7 +388,7 @@ public: bool CastNumericObject(TypeRelation *relation, Type *target); void IsSupertypeOf(TypeRelation *relation, Type *source) override; void IsSubtypeOf(TypeRelation *relation, Type *target) override; - Type *AsSuper(Checker *checker, varbinder::Variable *sourceVar) override; + Type *AsSuper(checker::Checker *checker, varbinder::Variable *sourceVar) override; void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override; static std::string NameToDescriptor(util::StringView name); void ToDebugInfoType(std::stringstream &ss) const override; @@ -392,7 +402,7 @@ public: const ArenaVector &ReExports() const; bool IsSameBasedGeneric(TypeRelation *relation, Type const *other) const; - ArenaAllocator *Allocator() const + ThreadSafeArenaAllocator *Allocator() const { return allocator_; } @@ -414,7 +424,7 @@ protected: private: template - explicit ETSObjectType(ArenaAllocator *allocator, util::StringView name, util::StringView assemblerName, + explicit ETSObjectType([[maybe_unused]] ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView assemblerName, std::tuple info, [[maybe_unused]] std::index_sequence s) : Type(TypeFlag::ETS_OBJECT), @@ -448,7 +458,7 @@ private: void IdenticalUptoTypeArguments(TypeRelation *relation, Type *other); void SubstitutePartialTypes(TypeRelation *relation, Type *other); void IsGenericSupertypeOf(TypeRelation *relation, ETSObjectType *source); - void UpdateTypeProperty(checker::ETSChecker *checker, varbinder::LocalVariable *const prop, PropertyType fieldType, + void UpdateTypeProperty(varbinder::LocalVariable *const prop, PropertyType fieldType, PropertyProcesser const &func); varbinder::LocalVariable *SearchFieldsDecls(const util::StringView &name, PropertySearchFlags flags) const; @@ -464,7 +474,7 @@ private: ir::TSTypeParameterDeclaration *GetTypeParams() const; - ArenaAllocator *const allocator_; + ThreadSafeArenaAllocator *const allocator_; util::StringView const name_; util::StringView const internalName_; ir::AstNode *const declNode_; @@ -477,6 +487,7 @@ private: ETSObjectType *superType_ {}; ETSObjectType *enclosingType_ {}; ETSObjectType *baseType_ {}; + std::shared_mutex instantiationMapMutex_; // for lazy properties instantiation TypeRelation *relation_ = nullptr; diff --git a/ets2panda/checker/types/ets/etsResizableArrayType.h b/ets2panda/checker/types/ets/etsResizableArrayType.h index 43babf404a36dcfdbce983333683b9a94a0666bd..1301e726931f457b658e626b915696d2f01a50d1 100644 --- a/ets2panda/checker/types/ets/etsResizableArrayType.h +++ b/ets2panda/checker/types/ets/etsResizableArrayType.h @@ -23,7 +23,7 @@ namespace ark::es2panda::checker { class ETSResizableArrayType : public ETSObjectType { public: - explicit ETSResizableArrayType(ArenaAllocator *allocator, ETSObjectType *super) + explicit ETSResizableArrayType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_ARRAY, nullptr, ETSObjectFlags::CLASS | ETSObjectFlags::BUILTIN_ARRAY | ETSObjectFlags::RESOLVED_SUPER), element_(nullptr) @@ -31,13 +31,13 @@ public: SetSuperType(super); } - explicit ETSResizableArrayType(ArenaAllocator *allocator, util::StringView name, + explicit ETSResizableArrayType(ThreadSafeArenaAllocator *allocator, util::StringView name, std::tuple info) : ETSObjectType(allocator, name, compiler::Signatures::BUILTIN_ARRAY, info), element_(nullptr) { } - explicit ETSResizableArrayType(ArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, + explicit ETSResizableArrayType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, Type *element) : ETSObjectType( allocator, "", compiler::Signatures::BUILTIN_ARRAY, diff --git a/ets2panda/checker/types/ets/etsStringType.h b/ets2panda/checker/types/ets/etsStringType.h index 2e47f48eea53295796b17ada5234f95891e6c5ae..be053026e49900e4fac66200501c587d7f746d3b 100644 --- a/ets2panda/checker/types/ets/etsStringType.h +++ b/ets2panda/checker/types/ets/etsStringType.h @@ -21,14 +21,14 @@ namespace ark::es2panda::checker { class ETSStringType : public ETSObjectType { public: - explicit ETSStringType(ArenaAllocator *allocator, ETSObjectType *super) + explicit ETSStringType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_STRING, nullptr, ETSObjectFlags::CLASS | ETSObjectFlags::STRING | ETSObjectFlags::RESOLVED_SUPER) { SetSuperType(super); } - explicit ETSStringType(ArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation) + explicit ETSStringType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_STRING, std::make_tuple(nullptr, ETSObjectFlags::CLASS | ETSObjectFlags::STRING | ETSObjectFlags::RESOLVED_SUPER, @@ -37,7 +37,7 @@ public: SetSuperType(super); } - explicit ETSStringType(ArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, + explicit ETSStringType(ThreadSafeArenaAllocator *allocator, ETSObjectType *super, TypeRelation *relation, util::StringView value) : ETSObjectType(allocator, "", compiler::Signatures::BUILTIN_STRING, std::make_tuple(nullptr, diff --git a/ets2panda/checker/types/type.cpp b/ets2panda/checker/types/type.cpp index 1c77f6fccca89d7d396d7c7ed3a149e4607c9b27..26fc13d371d6861068bc64ceaee303425d53306a 100644 --- a/ets2panda/checker/types/type.cpp +++ b/ets2panda/checker/types/type.cpp @@ -22,6 +22,8 @@ namespace ark::es2panda::checker { +Spinlock Type::idLock_ = Spinlock(); + bool Type::IsETSResizableArrayType() const { return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_ARRAY); diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index 1a0895b37a62d2824bab0b9fbf52314c9f7a80e5..41dcebeeca78ecd85171b1e89ba6743d49989015 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -50,14 +50,17 @@ class Type { public: explicit Type(TypeFlag flag) : typeFlags_(flag) { + idLock_.lock(); static uint64_t typeId = 0; id_ = ++typeId; + idLock_.unlock(); } NO_COPY_SEMANTIC(Type); NO_MOVE_SEMANTIC(Type); virtual ~Type() = default; + static Spinlock idLock_; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define TYPE_IS_CHECKS(typeFlag, typeName) \ diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index ea7f55889c26061accaf588457df0c9de33de43f..2ebd20dd9779b9554c0978dc385ba6d9e2a8bdbb 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -97,7 +97,7 @@ void ETSGen::CompileAndCheck(const ir::Expression *expr) const checker::ETSChecker *ETSGen::Checker() const noexcept { - return Context()->checker->AsETSChecker(); + return Context()->GetChecker()->AsETSChecker(); } const varbinder::ETSBinder *ETSGen::VarBinder() const noexcept diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index a64eee6047b1170fa227d70a00739a43723ebdbc..bdba085e6eb1ed575ea103d95fa7a9bee523c6e7 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -234,13 +234,13 @@ static void StoreEntity(std::vector &literals, u } static std::vector> StoreExportNodes( - std::vector> &declGen, pandasm::Program *program) + ArenaUnorderedMap &declGen, pandasm::Program *program) { std::vector literals; std::vector> result; for (auto &pair : declGen) { - auto declString = pair.first; + auto declString = std::string {pair.first}; auto *node = pair.second; if (node->IsClassProperty() && node->IsConst()) { StoreEntity(literals, parser::EntityType::CLASS_PROPERTY); @@ -291,7 +291,7 @@ void ETSEmitter::GenAnnotation() if (scriptFunc->IsAsyncFunc()) { std::vector annotations; annotations.push_back(GenAnnotationAsync(scriptFunc)); - func.metadata->SetAnnotations(std::move(annotations)); + func.metadata->AddAnnotations(std::move(annotations)); } Program()->AddToFunctionTable(std::move(func)); } @@ -303,7 +303,7 @@ void ETSEmitter::GenAnnotation() GenExternalRecord(recordTable, extProg); } - const auto *checker = static_cast(Context()->checker); + const auto *checker = static_cast(Context()->GetChecker()); for (auto [arrType, signature] : checker->GlobalArrayTypes()) { GenGlobalArrayRecord(arrType, signature); @@ -340,7 +340,7 @@ void ETSEmitter::GenExternalRecord(varbinder::RecordTable *recordTable, const pa GenInterfaceRecord(interfaceDecl, !isGenStdLib); } - for (auto *signature : recordTable->Signatures()) { + for (auto const *signature : recordTable->Signatures()) { auto func = GenScriptFunction(signature->Node()->AsScriptFunction(), this); if (!isGenStdLib) { @@ -348,7 +348,7 @@ void ETSEmitter::GenExternalRecord(varbinder::RecordTable *recordTable, const pa } if (func.metadata->IsForeign() && IsFromSelfHeadFile(func.name, Context()->parserProgram, extProg)) { - return; + continue; } if (Program()->functionStaticTable.find(func.name) == Program()->functionStaticTable.cend()) { @@ -543,7 +543,7 @@ std::vector ETSEmitter::GenAnnotations(const ir::ClassD auto classIdent = classDef->Ident()->Name().Mutf8(); bool isConstruct = classIdent == Signatures::JSNEW_CLASS; if (isConstruct || classIdent == Signatures::JSCALL_CLASS) { - auto *callNames = Context()->checker->AsETSChecker()->DynamicCallNames(isConstruct); + auto *callNames = Context()->GetChecker()->AsETSChecker()->DynamicCallNames(isConstruct); annotations.push_back(GenAnnotationDynamicCall(*callNames)); } @@ -752,7 +752,7 @@ LiteralArrayVector ETSEmitter::CreateLiteralArray(std::string &baseName, const i void ETSEmitter::CreateLiteralArrayProp(const ir::ClassProperty *prop, std::string &baseName, pandasm::Field &field) { - auto *checker = Context()->checker->AsETSChecker(); + auto *checker = Context()->GetChecker()->AsETSChecker(); uint8_t rank = 1; auto *elemType = checker->GetElementTypeOfArray(prop->TsType()); while (elemType->IsETSArrayType() || elemType->IsETSResizableArrayType()) { @@ -870,7 +870,7 @@ pandasm::AnnotationElement ETSEmitter::GenCustomAnnotationElement(const ir::Clas return ProcessETSEnumType(baseName, init, type); } switch (checker::ETSChecker::TypeKind( - Context()->checker->AsETSChecker()->MaybeUnboxType(const_cast(type)))) { + Context()->GetChecker()->AsETSChecker()->MaybeUnboxType(const_cast(type)))) { case checker::TypeFlag::BYTE: case checker::TypeFlag::SHORT: case checker::TypeFlag::INT: @@ -1050,7 +1050,7 @@ ir::MethodDefinition *ETSEmitter::FindAsyncImpl(ir::ScriptFunction *asyncFunc) } ir::MethodDefinition *method = (*it)->AsMethodDefinition(); - auto *checker = static_cast(Context()->checker); + auto *checker = static_cast(Context()->GetChecker()); checker::TypeRelation *typeRel = checker->Relation(); checker::SavedTypeRelationFlagsContext savedFlagsCtx(typeRel, checker::TypeRelationFlag::NO_RETURN_TYPE_CHECK); method->Function()->Signature()->IsSubtypeOf(typeRel, asyncFunc->Signature()); diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 0f92b8a1bc226f914ed189dedf07c15e5becc09e..4092ef76211f360ac161c8b0437b3ea57f2c76b7 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -48,6 +48,8 @@ #include "public/public.h" #include "util/diagnosticEngine.h" +#include + namespace ark::es2panda::compiler { void CompilerImpl::HandleContextLiterals(public_lib::Context *context) @@ -156,6 +158,11 @@ static bool RunVerifierAndPhases(public_lib::Context &context, parser::Program & return false; } + if (phase->Name() == "CheckerPhase") { + Recheck(context.phaseManager, context.GetChecker()->VarBinder()->AsETSBinder(), + context.GetChecker()->AsETSChecker(), program.Ast()); + } + if (verifier.IntroduceNewInvariants(phase->Name()); verifierEachPhase || options.HasVerifierPhase(phase->Name())) { verifier.Verify(phase->Name()); @@ -217,18 +224,28 @@ static void CreateDebuggerEvaluationPlugin(checker::ETSChecker &checker, ArenaAl } } +static void MarkAsLowered(parser::Program &program){ + for (auto &[name, extPrograms] : program.ExternalSources()) { + for (auto &extProgram : extPrograms) { + extProgram->MarkASTAsLowered(); + } + } +} + template // CC-OFFNXT(huge_method, G.FUN.01-CPP) solid logic static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *compilerImpl) { - ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + ir::g_mainFileDisableHistory = false; + ThreadSafeArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + auto phaseManager = compiler::PhaseManager(unit.ext, &allocator); auto program = parser::Program::NewProgram(&allocator); auto parser = Parser(&program, unit.options, unit.diagnosticEngine, static_cast(unit.rawParserStatus)); auto checker = Checker(unit.diagnosticEngine); auto analyzer = Analyzer(&checker); - auto phaseManager = compiler::PhaseManager(unit.ext, &allocator); + checker.SetAnalyzer(&analyzer); auto *varbinder = program.VarBinder(); @@ -248,9 +265,9 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp context.queue = compilerImpl->Queue(); context.plugins = &compilerImpl->Plugins(); context.parser = &parser; - context.checker = &checker; - context.analyzer = checker.GetAnalyzer(); context.parserProgram = &program; + context.PushChecker(&checker); + context.PushAnalyzer(checker.GetAnalyzer()); context.codeGenCb = MakeCompileJob(); context.diagnosticEngine = &unit.diagnosticEngine; context.phaseManager = &phaseManager; @@ -258,8 +275,9 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp auto emitter = Emitter(&context); context.emitter = &emitter; + parser.SetContext(&context); varbinder->SetContext(&context); - context.checker->Initialize(varbinder); + context.GetChecker()->Initialize(varbinder); parser.ParseScript(unit.input, unit.options.GetCompilationMode() == CompilationMode::GEN_STD_LIB); @@ -282,6 +300,161 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp return nullptr; } + if (context.config->options->GetCompilationMode() == CompilationMode::GEN_STD_LIB) { + emitter.GenAnnotation(); + return compilerImpl->Emit(&context); + } + emitter.GenAnnotation(); + [[maybe_unused]] auto prog1 = compilerImpl->Emit(&context); + // return prog1; + + // new 2 + auto diagnosticEngine2 = util::DiagnosticEngine(); + diagnosticEngine2.SetWError(false); + auto phaseManager2 = compiler::PhaseManager(unit.ext, &allocator); + util::DiagnosticEngine::InitializeSignalHandlers(); + auto program2 = parser::Program::NewProgram(&allocator); + auto parser2 = + Parser(&program2, unit.options, diagnosticEngine2, static_cast(unit.rawParserStatus)); + + auto checker2 = Checker(diagnosticEngine2); + auto analyzer2 = Analyzer(&checker2); + + checker2.SetAnalyzer(&analyzer2); + + auto *varbinder2 = program2.VarBinder(); + varbinder2->SetProgram(&program2); + + if constexpr (std::is_same_v) { + CreateDebuggerEvaluationPlugin(checker2, allocator, &program2, unit.options); + } + + public_lib::Context context2; + auto config2 = public_lib::ConfigImpl {}; + context2.config = &config2; + context2.config->options = &unit.options; + context2.sourceFile = &unit.input; + context2.allocator = &allocator; + context2.queue = compilerImpl->Queue(); + context2.plugins = &compilerImpl->Plugins(); + context2.parser = &parser2; + context2.parserProgram = &program2; + context2.PushChecker(&checker2); + context2.PushAnalyzer(checker2.GetAnalyzer()); + context2.codeGenCb = MakeCompileJob(); + + context2.diagnosticEngine = &diagnosticEngine2; + context2.phaseManager = &phaseManager2; + + auto emitter2 = Emitter(&context2); + context2.emitter = &emitter2; + + parser2.SetContext(&context2); + + varbinder2->SetContext(&context2); + context2.GetChecker()->Initialize(varbinder2); + + SetPhaseManager(&phaseManager2); + + parser2.ParseScript(unit.input, unit.options.GetCompilationMode() == CompilationMode::GEN_STD_LIB); + + // copy work 1 + + checker2.SetGlobalTypesHolder(checker.GetGlobalTypesHolder()); + MarkAsLowered(program); + //program2.MarkASTAsLowered(); + + for (auto &it : program.ExternalSources()) { + program2.ExternalSources().insert_or_assign(it.first, it.second); + } + + if (!RunVerifierAndPhases(context2, program2)) { + return nullptr; + } + + emitter2.GenAnnotation(); + [[maybe_unused]] auto prog2 = compilerImpl->Emit(&context2); + context2.diagnosticEngine->ClearDiagnostics(); + // return prog2; + + /// new 3 + + // new + auto diagnosticEngine3 = util::DiagnosticEngine(); + diagnosticEngine3.SetWError(false); + auto phaseManager3 = compiler::PhaseManager(unit.ext, &allocator); + util::DiagnosticEngine::InitializeSignalHandlers(); + auto program3 = parser::Program::NewProgram(&allocator); + auto parser3 = + Parser(&program3, unit.options, diagnosticEngine3, static_cast(unit.rawParserStatus)); + + auto checker3 = Checker(diagnosticEngine3); + auto analyzer3 = Analyzer(&checker3); + + checker3.SetAnalyzer(&analyzer3); + + auto *varbinder3 = program3.VarBinder(); + varbinder3->SetProgram(&program3); + + if constexpr (std::is_same_v) { + CreateDebuggerEvaluationPlugin(checker3, allocator, &program3, unit.options); + } + + public_lib::Context context3; + auto config3 = public_lib::ConfigImpl {}; + context3.config = &config3; + context3.config->options = &unit.options; + context3.sourceFile = &unit.input; + context3.allocator = &allocator; + context3.queue = compilerImpl->Queue(); + context3.plugins = &compilerImpl->Plugins(); + context3.parser = &parser3; + context3.parserProgram = &program3; + context3.PushChecker(&checker3); + context3.PushAnalyzer(checker3.GetAnalyzer()); + context3.codeGenCb = MakeCompileJob(); + + context3.diagnosticEngine = &diagnosticEngine3; + context3.phaseManager = &phaseManager3; + + auto emitter3 = Emitter(&context3); + context3.emitter = &emitter3; + + parser3.SetContext(&context3); + varbinder3->SetContext(&context3); + context3.GetChecker()->Initialize(varbinder3); + + SetPhaseManager(&phaseManager3); + + parser3.ParseScript(unit.input, unit.options.GetCompilationMode() == CompilationMode::GEN_STD_LIB); + + // copy work 1 + + checker3.SetGlobalTypesHolder(checker.GetGlobalTypesHolder()); + MarkAsLowered(program); + //program3.MarkASTAsLowered(); + + for (auto &it : program.ExternalSources()) { + program3.ExternalSources().insert_or_assign(it.first, it.second); + } + + if (!RunVerifierAndPhases(context3, program3)) { + return nullptr; + } + + emitter3.GenAnnotation(); + [[maybe_unused]] auto prog3 = compilerImpl->Emit(&context3); + context3.diagnosticEngine->ClearDiagnostics(); + + return prog3; + + //#ifndef NDEBUG + // CompileForAstCache(unit,compilerImpl,allocator,context); + // return CompileForAstCache(unit,compilerImpl,allocator,context); + //#endif + emitter.GenAnnotation(); return compilerImpl->Emit(&context); } diff --git a/ets2panda/compiler/core/pandagen.cpp b/ets2panda/compiler/core/pandagen.cpp index 85ab16b5455323a15f78a485dab62313595ce5a3..3438850966073a81539b9ef3fa910ff7b9dd2a7e 100644 --- a/ets2panda/compiler/core/pandagen.cpp +++ b/ets2panda/compiler/core/pandagen.cpp @@ -1825,7 +1825,7 @@ const checker::Type *PandaGen::GetVRegType(VReg vreg) const { // We assume that all used regs have any type if (vreg.GetIndex() > NextReg().GetIndex()) { - return Context()->checker->GetGlobalTypesHolder()->GlobalAnyType(); + return Context()->GetChecker()->GetGlobalTypesHolder()->GlobalAnyType(); } return nullptr; diff --git a/ets2panda/compiler/lowering/checkerPhase.cpp b/ets2panda/compiler/lowering/checkerPhase.cpp index 019a5ce570f922d4e512c432f22a286d11c05848..415f2fcff4a6f5a9cf23167a10f6975cef6d7c00 100644 --- a/ets2panda/compiler/lowering/checkerPhase.cpp +++ b/ets2panda/compiler/lowering/checkerPhase.cpp @@ -15,21 +15,32 @@ #include "checkerPhase.h" #include "checker/checker.h" +#include "checker/ETSchecker.h" namespace ark::es2panda::compiler { +void CheckerPhase::FetchCache(public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) +{ + // for ast-cache using + ctx->GetChecker()->AsETSChecker()->ReputCheckerData(); +} + bool CheckerPhase::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) { + ctx->GetChecker()->Initialize(program->VarBinder()); + FetchCache(ctx, program); for (auto [_, programList] : program->ExternalSources()) { for (auto prog : programList) { - for (auto stmt : prog->Ast()->Statements()) { - stmt->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP); + if (!prog->IsASTLowered()) { + for (auto stmt : prog->Ast()->Statements()) { + stmt->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP); + } } } } for (auto stmt : program->Ast()->Statements()) { stmt->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP); } - auto checkerResult = ctx->checker->StartChecker(ctx->parserProgram->VarBinder(), *ctx->config->options); + auto checkerResult = ctx->GetChecker()->StartChecker(ctx->parserProgram->VarBinder(), *ctx->config->options); return checkerResult; } diff --git a/ets2panda/compiler/lowering/checkerPhase.h b/ets2panda/compiler/lowering/checkerPhase.h index 03b9e6979b12a3d326a1b34b60f90a870b110652..d5b1b48cad2fc83e4fc9758f2dd5734a50dede6b 100644 --- a/ets2panda/compiler/lowering/checkerPhase.h +++ b/ets2panda/compiler/lowering/checkerPhase.h @@ -26,6 +26,7 @@ public: { return NAME; } + void FetchCache(public_lib::Context *ctx, parser::Program *program) override; bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp index a9aa187de82ac2c266206b969e1b8ef6a7812535..bf9fea2cc5a6552378dff92248dfff73ac4d9e89 100644 --- a/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp @@ -231,7 +231,7 @@ bool ArrayLiteralLowering::PerformForModule(public_lib::Context *ctx, parser::Pr { parser_ = ctx->parser->AsETSParser(); varbinder_ = ctx->parserProgram->VarBinder()->AsETSBinder(); - checker_ = ctx->checker->AsETSChecker(); + checker_ = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( [this](ir::AstNode *ast) -> AstNodePtr { if (ast->IsArrayExpression()) { diff --git a/ets2panda/compiler/lowering/ets/asyncMethodLowering.cpp b/ets2panda/compiler/lowering/ets/asyncMethodLowering.cpp index d801b5526c23dc6f88d31f35fcc4c16c3a85e444..23c6244780d5435803fad31ebd96c42d31c2b02f 100644 --- a/ets2panda/compiler/lowering/ets/asyncMethodLowering.cpp +++ b/ets2panda/compiler/lowering/ets/asyncMethodLowering.cpp @@ -126,7 +126,7 @@ ir::MethodDefinition *CreateAsyncProxy(checker::ETSChecker *checker, ir::MethodD { ir::ScriptFunction *asyncFunc = asyncMethod->Function(); if (!asyncFunc->IsExternal()) { - checker->VarBinder()->AsETSBinder()->GetRecordTable()->Signatures().push_back(asyncFunc->Scope()); + checker->VarBinder()->AsETSBinder()->GetRecordTable()->EmplaceSignatures(asyncFunc->Scope(), asyncFunc); } ir::MethodDefinition *implMethod = CreateAsyncImplMethod(checker, asyncMethod, classDef); @@ -199,7 +199,7 @@ void UpdateClassDefintion(checker::ETSChecker *checker, ir::ClassDefinition *cla bool AsyncMethodLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); ir::NodeTransformer handleClassAsyncMethod = [checker](ir::AstNode *const ast) { if (ast->IsClassDefinition()) { diff --git a/ets2panda/compiler/lowering/ets/bigintLowering.cpp b/ets2panda/compiler/lowering/ets/bigintLowering.cpp index 132656ee5c82e10a0ed64a7d79d6f5eb698410cd..5beaf4538ecfb7b1b2ea96e34005571357f37649 100644 --- a/ets2panda/compiler/lowering/ets/bigintLowering.cpp +++ b/ets2panda/compiler/lowering/ets/bigintLowering.cpp @@ -28,7 +28,7 @@ std::string_view BigIntLowering::Name() const ir::Expression *CreateBigInt(public_lib::Context *ctx, ir::BigIntLiteral *literal) { auto parser = ctx->parser->AsETSParser(); - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); // This will change the bigint literal node into the new class instance expression: // 123456n => new BigInt("123456") @@ -90,7 +90,7 @@ bool RemoveConst(ir::BinaryExpression *expr) bool BigIntLowering::PerformForModule(public_lib::Context *const ctx, parser::Program *const program) { - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( // CC-OFFNXT(G.FMT.14-CPP) project code style diff --git a/ets2panda/compiler/lowering/ets/boxedTypeLowering.cpp b/ets2panda/compiler/lowering/ets/boxedTypeLowering.cpp index 5ede67cba95b3851f36b61bdd36b83686d7acaa8..e34a661fa6bad35693722f231816c56972a2032f 100644 --- a/ets2panda/compiler/lowering/ets/boxedTypeLowering.cpp +++ b/ets2panda/compiler/lowering/ets/boxedTypeLowering.cpp @@ -59,17 +59,9 @@ void BoxNumberLiteralArguments(ir::CallExpression *callExpr, PhaseManager *phase } } } - -bool BoxedTypeLowering::Perform(public_lib::Context *const ctx, parser::Program *const program) +bool BoxedTypeLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - for (const auto &[_, ext_programs] : program->ExternalSources()) { - (void)_; - for (auto *const extProg : ext_programs) { - Perform(ctx, extProg); - } - } - - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); auto parser = ctx->parser->AsETSParser(); auto phaseManager = ctx->phaseManager; program->Ast()->TransformChildrenRecursively( @@ -91,7 +83,6 @@ bool BoxedTypeLowering::Perform(public_lib::Context *const ctx, parser::Program return ast; }, Name()); - return true; } diff --git a/ets2panda/compiler/lowering/ets/boxedTypeLowering.h b/ets2panda/compiler/lowering/ets/boxedTypeLowering.h index cf124f55bb29375e856e38d1df440d4265a45aef..94eafe9e90d83a9dc7a5315dd564563a0ad89fa4 100644 --- a/ets2panda/compiler/lowering/ets/boxedTypeLowering.h +++ b/ets2panda/compiler/lowering/ets/boxedTypeLowering.h @@ -20,10 +20,11 @@ namespace ark::es2panda::compiler { -class BoxedTypeLowering : public Phase { +class BoxedTypeLowering : public PhaseForDeclarations { public: std::string_view Name() const override; - bool Perform(public_lib::Context *ctx, parser::Program *program) override; + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/boxingForLocals.cpp b/ets2panda/compiler/lowering/ets/boxingForLocals.cpp index 2f63e74222530e2f0edf6d3029c46af1fd5eb825..81e980c3b861e67571bb6a6a40dccf834ef1c433 100644 --- a/ets2panda/compiler/lowering/ets/boxingForLocals.cpp +++ b/ets2panda/compiler/lowering/ets/boxingForLocals.cpp @@ -119,7 +119,7 @@ static void HandleFunctionParam(public_lib::Context *ctx, ir::ETSParameterExpres ArenaMap *varsMap) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *varBinder = checker->VarBinder(); auto *id = param->Ident()->AsIdentifier(); @@ -128,7 +128,7 @@ static void HandleFunctionParam(public_lib::Context *ctx, ir::ETSParameterExpres auto *func = param->Parent()->AsScriptFunction(); ES2PANDA_ASSERT(func->Body()->IsBlockStatement()); // guaranteed after expressionLambdaLowering auto *body = func->Body()->AsBlockStatement(); - auto &bodyStmts = body->Statements(); + auto &bodyStmts = body->StatmentsForUpdates(); auto *scope = body->Scope(); auto *initId = allocator->New(id->Name(), allocator); @@ -177,7 +177,7 @@ static ir::AstNode *HandleVariableDeclarator(public_lib::Context *ctx, ir::Varia ArenaMap *varsMap) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *varBinder = checker->VarBinder(); auto *id = declarator->Id()->AsIdentifier(); @@ -231,7 +231,7 @@ static bool IsBeingDeclared(ir::AstNode *ast) static bool IsPartOfBoxInitializer(public_lib::Context *ctx, ir::AstNode *ast) { ES2PANDA_ASSERT(ast->IsIdentifier()); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *id = ast->AsIdentifier(); // NOTE(gogabr): rely on caching for type instantiations, so we can use pointer comparison. @@ -248,7 +248,7 @@ static bool OnLeftSideOfAssignment(ir::AstNode *ast) static ir::AstNode *HandleReference(public_lib::Context *ctx, ir::Identifier *id, varbinder::Variable *var) { auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); // `as` is needed to account for smart types auto *res = parser->CreateFormattedExpression("@@I1.get() as @@T2", var->Name(), id->TsType()); @@ -279,8 +279,8 @@ static ir::AstNode *HandleAssignment(public_lib::Context *ctx, ir::AssignmentExp ES2PANDA_ASSERT(ass->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION); auto *parser = ctx->parser->AsETSParser(); - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); - auto *checker = ctx->checker->AsETSChecker(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *oldVar = ass->Left()->Variable(); auto *newVar = varsMap.find(oldVar)->second; diff --git a/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp b/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp index 823859d6819d8f9843887e6b86b0bb5b0b0087a3..0a3374acc29ed51294a32aa3902c52e7c829727d 100644 --- a/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp +++ b/ets2panda/compiler/lowering/ets/cfgBuilderPhase.cpp @@ -28,7 +28,9 @@ bool CFGBuilderPhase::Perform(public_lib::Context *ctx, parser::Program *program for (auto &[_, ext_programs] : program->ExternalSources()) { (void)_; for (auto *extProg : ext_programs) { - Perform(ctx, extProg); + if (!extProg->IsASTLowered()) { + Perform(ctx, extProg); + } } } diff --git a/ets2panda/compiler/lowering/ets/constStringToCharLowering.cpp b/ets2panda/compiler/lowering/ets/constStringToCharLowering.cpp index 73a1658357880f22c5fd79e266c3322371fc8439..c0c3f09d7ede3588d888eab3c89cf7fa7df1e00d 100644 --- a/ets2panda/compiler/lowering/ets/constStringToCharLowering.cpp +++ b/ets2panda/compiler/lowering/ets/constStringToCharLowering.cpp @@ -53,7 +53,7 @@ ir::AstNode *TryConvertToCharLiteral(checker::ETSChecker *checker, ir::AstNode * bool ConstStringToCharLowering::PerformForModule(public_lib::Context *const ctx, parser::Program *const program) { - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( // CC-OFFNXT(G.FMT.14-CPP) project code style diff --git a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp index c3e7ebbb6dc506c4e6d5172560bb2a76a7d1eb91..66543d0f24d7b4c87d219cbf9d98b4f5ef14b05a 100644 --- a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp +++ b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp @@ -24,7 +24,7 @@ namespace ark::es2panda::compiler { void GenerateOverloadHelperParams(public_lib::Context *ctx, uint32_t minArg, size_t maxArg, bool hasRestVar, ArenaVector ¶ms) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; if (!hasRestVar) { @@ -59,9 +59,9 @@ void GenerateOverloadHelperParams(public_lib::Context *ctx, uint32_t minArg, siz void BuildOverloadHelperFunction(public_lib::Context *ctx, ir::MethodDefinition *method) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); auto const &[minArg, maxArg, needHelperOverload, isDeclare, hasRestVar, returnVoid] = method->GetOverloadInfo(); ES2PANDA_ASSERT(needHelperOverload); @@ -108,7 +108,7 @@ void UpdateCallSignature(public_lib::Context *ctx, ir::CallExpression *expr) { ES2PANDA_ASSERT(expr->Signature()->HasSignatureFlag(checker::SignatureFlags::DUPLICATE_ASM)); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); expr->SetTsType(nullptr); expr->Check(checker); } diff --git a/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp b/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp index d9ede70dc70e83d757ebbd3be280e8859230dada..44c422f9f0b345d74fdc6720660ba8497aabfc83 100644 --- a/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp +++ b/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp @@ -185,7 +185,7 @@ static void CreateFunctionOverload(ir::MethodDefinition *method, ArenaVectorSetRange(funcExpression->Range()); if (!method->IsDeclare() && method->Parent()->IsTSInterfaceBody()) { - overloadMethod->Function()->Body()->AsBlockStatement()->Statements().clear(); + overloadMethod->Function()->Body()->AsBlockStatement()->ClearStatements(); } method->AddOverload(overloadMethod); diff --git a/ets2panda/compiler/lowering/ets/defaultParametersLowering.cpp b/ets2panda/compiler/lowering/ets/defaultParametersLowering.cpp index d87fc777fd5283328aa9c22b3f21b944ac3cc7c2..0ed81cdd9a62dd29cdcae281e61921e8edf10f95 100644 --- a/ets2panda/compiler/lowering/ets/defaultParametersLowering.cpp +++ b/ets2panda/compiler/lowering/ets/defaultParametersLowering.cpp @@ -68,13 +68,14 @@ static void TransformFunction(public_lib::Context *ctx, ir::ScriptFunction *func auto const body = function->Body()->AsBlockStatement(); auto const allocator = ctx->allocator; auto const parser = ctx->parser->AsETSParser(); + auto &bodyStmt = body->StatmentsForUpdates(); - body->Statements().insert(body->Statements().begin(), defaultParams.size(), nullptr); + bodyStmt.insert(bodyStmt.begin(), defaultParams.size(), nullptr); for (size_t dfltIdx = 0; dfltIdx < defaultParams.size(); ++dfltIdx) { auto const param = defaultParams.at(dfltIdx); auto stmt = TransformInitializer(allocator, parser, param); - body->Statements()[dfltIdx] = stmt; + bodyStmt[dfltIdx] = stmt; stmt->SetParent(body); } } diff --git a/ets2panda/compiler/lowering/ets/dynamicImportLowering.cpp b/ets2panda/compiler/lowering/ets/dynamicImportLowering.cpp index 8cf9e00c33ef2a8b5a14e7a5285320e4d272e7ae..b4d6f19d1bedad6287b17d2dc3b2a8a4c185ddb7 100644 --- a/ets2panda/compiler/lowering/ets/dynamicImportLowering.cpp +++ b/ets2panda/compiler/lowering/ets/dynamicImportLowering.cpp @@ -21,7 +21,7 @@ namespace ark::es2panda::compiler { bool DynamicImportLowering::PerformForModule(public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) { - ctx->checker->AsETSChecker()->BuildDynamicImportClass(); + ctx->GetChecker()->AsETSChecker()->BuildDynamicImportClass(); return true; } diff --git a/ets2panda/compiler/lowering/ets/enumLowering.cpp b/ets2panda/compiler/lowering/ets/enumLowering.cpp index 6566ac9d607c532eb024eca5711de588fa3e53ce..2b9b8dc9e38da710ef92ab46365ef003dc428e8f 100644 --- a/ets2panda/compiler/lowering/ets/enumLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumLowering.cpp @@ -383,7 +383,7 @@ ir::ScriptFunction *EnumLoweringPhase::CreateFunctionForCtorOfEnumClass(ir::Clas checker_->AllocNode(callee, std::move(callArguments), nullptr, false); auto *superCallStatement = checker_->AllocNode(superConstructorCall); superCallStatement->SetParent(body); - body->Statements().push_back(superCallStatement); + body->AddStatement(superCallStatement); auto *thisExpr = Allocator()->New(); auto *fieldIdentifier = Allocator()->New(ORDINAL_NAME, Allocator()); @@ -395,7 +395,7 @@ ir::ScriptFunction *EnumLoweringPhase::CreateFunctionForCtorOfEnumClass(ir::Clas lexer::TokenType::PUNCTUATOR_SUBSTITUTION); auto initStatement = checker_->AllocNode(initializer); initStatement->SetParent(body); - body->Statements().push_back(initStatement); + body->AddStatement(initStatement); return func; } @@ -541,7 +541,7 @@ bool EnumLoweringPhase::PerformForModule(public_lib::Context *ctx, parser::Progr } context_ = ctx; - checker_ = ctx->checker->AsETSChecker(); + checker_ = ctx->GetChecker()->AsETSChecker(); varbinder_ = ctx->parserProgram->VarBinder()->AsETSBinder(); program_ = program; diff --git a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp index 3fb0f59817c80ba2a19c7d2b8cf26203175ff824..e6dfe24557f81753d5b77ee8dd0375c72ca4c5a0 100644 --- a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp @@ -371,7 +371,7 @@ bool EnumPostCheckLoweringPhase::PerformForModule(public_lib::Context *ctx, pars } parser_ = ctx->parser->AsETSParser(); - checker_ = ctx->checker->AsETSChecker(); + checker_ = ctx->GetChecker()->AsETSChecker(); varbinder_ = ctx->parserProgram->VarBinder()->AsETSBinder(); program->Ast()->TransformChildrenRecursivelyPostorder( diff --git a/ets2panda/compiler/lowering/ets/expandBrackets.cpp b/ets2panda/compiler/lowering/ets/expandBrackets.cpp index 23b7769f88dcbc01196e47857c216d6a0b494ff3..f071f061f064ea0c4b37dcc92ff4203e3e7e205a 100644 --- a/ets2panda/compiler/lowering/ets/expandBrackets.cpp +++ b/ets2panda/compiler/lowering/ets/expandBrackets.cpp @@ -151,7 +151,7 @@ bool ExpandBracketsPhase::PerformForModule(public_lib::Context *ctx, parser::Pro { auto *const parser = ctx->parser->AsETSParser(); ES2PANDA_ASSERT(parser != nullptr); - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); ES2PANDA_ASSERT(checker != nullptr); program->Ast()->TransformChildrenRecursively( diff --git a/ets2panda/compiler/lowering/ets/expressionLambdaLowering.cpp b/ets2panda/compiler/lowering/ets/expressionLambdaLowering.cpp index be14976359ad1586a9eb169ccedf33933de23efa..9751fc9604e01448cd29e10a4a1e340625e65202 100644 --- a/ets2panda/compiler/lowering/ets/expressionLambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/expressionLambdaLowering.cpp @@ -47,7 +47,7 @@ using AstNodePtr = ir::AstNode *; bool ExpressionLambdaConstructionPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( [checker](ir::AstNode *const node) -> AstNodePtr { diff --git a/ets2panda/compiler/lowering/ets/extensionAccessorLowering.cpp b/ets2panda/compiler/lowering/ets/extensionAccessorLowering.cpp index 4c50938f215dec054b0e0d65a3e42a73a25adb87..77a0aeb3c026f1bc74c06554ee021f0d3b4aa4d8 100644 --- a/ets2panda/compiler/lowering/ets/extensionAccessorLowering.cpp +++ b/ets2panda/compiler/lowering/ets/extensionAccessorLowering.cpp @@ -133,7 +133,7 @@ bool ExtensionAccessorPhase::PerformForModule(public_lib::Context *ctx, parser:: return true; } - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( [&checker](ir::AstNode *const node) -> AstNodePtr { return CheckAndReturnNode(checker, node); }, Name()); return true; diff --git a/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp b/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp index 59f3c0a0ccd10925a47e7eb56dc91fff94eebaf7..44297af02c65c24a2d1ff12b2be20dff15577cf5 100644 --- a/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp +++ b/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp @@ -27,7 +27,7 @@ std::string GenericBridgesPhase::CreateMethodDefinitionString(ir::ClassDefinitio { constexpr std::size_t SOURCE_CODE_LENGTH = 128U; - auto *checker = context_->checker->AsETSChecker(); + auto *checker = context_->GetChecker()->AsETSChecker(); std::string str1 {}; str1.reserve(2U * SOURCE_CODE_LENGTH); @@ -93,7 +93,7 @@ void GenericBridgesPhase::AddGenericBridge(ir::ClassDefinition const *const clas bridgeMethod->AddAstNodeFlags(methodDefinition->GetAstNodeFlags()); bridgeMethod->SetParent(const_cast(classDefinition)); - auto *varBinder = context_->checker->VarBinder()->AsETSBinder(); + auto *varBinder = context_->GetChecker()->VarBinder()->AsETSBinder(); auto *scope = NearestScope(methodDefinition); auto scopeGuard = varbinder::LexicalScope::Enter(varBinder, scope); InitScopesPhaseETS::RunExternalNode(bridgeMethod, varBinder); @@ -102,7 +102,7 @@ void GenericBridgesPhase::AddGenericBridge(ir::ClassDefinition const *const clas true}; varBinder->AsETSBinder()->ResolveReferencesForScopeWithContext(bridgeMethod, scope); - auto *checker = context_->checker->AsETSChecker(); + auto *checker = context_->GetChecker()->AsETSChecker(); auto const checkerCtx = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_CLASS | checker::CheckerStatus::IGNORE_VISIBILITY | @@ -130,7 +130,7 @@ void GenericBridgesPhase::ProcessScriptFunction(ir::ClassDefinition const *const ir::MethodDefinition *const derivedMethod, Substitutions const &substitutions) const { - auto *const checker = context_->checker->AsETSChecker(); + auto *const checker = context_->GetChecker()->AsETSChecker(); auto *const relation = checker->Relation(); auto const overrides = [checker, relation, classDefinition](checker::Signature const *source, @@ -196,7 +196,7 @@ void GenericBridgesPhase::CreateGenericBridges(ir::ClassDefinition const *const auto const &classBody = classDefinition->Body(); // Collect type parameters defaults/constraints in the derived class - auto *checker = context_->checker->AsETSChecker(); + auto *checker = context_->GetChecker()->AsETSChecker(); substitutions.derivedConstraints = checker->NewSubstitution(); auto const *const classType = classDefinition->TsType()->AsETSObjectType(); @@ -236,7 +236,7 @@ GenericBridgesPhase::Substitutions GenericBridgesPhase::GetSubstitutions( auto const parameterNumber = typeParameters.size(); ES2PANDA_ASSERT(parameterNumber == typeArguments.size()); - auto *checker = context_->checker->AsETSChecker(); + auto *checker = context_->GetChecker()->AsETSChecker(); Substitutions substitutions {}; substitutions.derivedSubstitutions = checker->NewSubstitution(); substitutions.baseConstraints = checker->NewSubstitution(); diff --git a/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.cpp b/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.cpp index 4c5100e69b42c609d58e270956da42aed24cc50c..8888ad04586f6833616d8b9cd95160fba7a99c0a 100644 --- a/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.cpp +++ b/ets2panda/compiler/lowering/ets/insertOptionalParametersAnnotation.cpp @@ -98,7 +98,7 @@ static void TryInsertDefaultAnnotation(public_lib::Context *ctx, ir::AstNode *no auto methodFunc = methodDef->Function(); auto defaultAnno = CreateDefaultAnnotationUsageForFunction(ctx, methodFunc); if (defaultAnno != nullptr) { - methodFunc->Annotations().emplace_back(defaultAnno->AsAnnotationUsage()); + methodFunc->EmplaceAnnotations(defaultAnno->AsAnnotationUsage()); defaultAnno->SetParent(methodFunc); RefineSourceRanges(defaultAnno); } diff --git a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp index 4b5ff91757bb9add7804e2b5afd3815bfaf3e23e..bac6d3a99c7ea2bff7edb6550ee24d341a07c554 100644 --- a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.cpp @@ -22,6 +22,7 @@ namespace ark::es2panda::compiler { +static constexpr std::string_view OBJECT_LITERAL_SUFFIX = "$ObjectLiteral"; using ReadonlyFieldHolder = std::tuple; // anonClassFieldName, paramName, fieldType @@ -46,7 +47,7 @@ static inline bool IsAbstractClassType(const checker::Type *type) static ir::AstNode *CreateAnonClassImplCtor(public_lib::Context *ctx, ArenaVector &readonlyFields) { - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); auto *const parser = ctx->parser->AsETSParser(); checker::ETSChecker::ClassInitializerBuilder initBuilder = [checker, parser, readonlyFields](ArenaVector *statements, @@ -122,23 +123,25 @@ static ir::MethodDefinition *CreateAnonClassFieldGetterSetter(public_lib::Contex } static void FillClassBody(public_lib::Context *ctx, ArenaVector *classBody, - const ArenaVector &ifaceBody, ir::ObjectExpression *objExpr, - ArenaVector &readonlyFields, + const ArenaVector &ifaceBody, ArenaVector &readonlyFields, checker::ETSObjectType *currentType = nullptr) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); for (auto *it : ifaceBody) { ES2PANDA_ASSERT(it->IsMethodDefinition()); auto *ifaceMethod = it->AsMethodDefinition(); - if (!ifaceMethod->Function()->IsGetter() && !ifaceMethod->Function()->IsSetter()) { - checker->LogError(diagnostic::INTERFACE_WITH_METHOD, {}, objExpr->Start()); - objExpr->SetTsType(checker->GlobalTypeError()); - return; + if (!ifaceMethod->Function()->IsGetter()) { + continue; } - if (!ifaceMethod->Function()->IsGetter()) { + auto iter = std::find_if(classBody->begin(), classBody->end(), [ifaceMethod](ir::AstNode *ast) -> bool { + return ast->IsMethodDefinition() && ast->AsMethodDefinition()->Function()->IsGetter() && + ast->AsMethodDefinition()->Id()->Name() == ifaceMethod->Id()->Name(); + }); + + if (iter != classBody->end()) { continue; } @@ -180,37 +183,35 @@ static void FillClassBody(public_lib::Context *ctx, ArenaVector * } static void FillAnonClassBody(public_lib::Context *ctx, ArenaVector *classBody, - ir::TSInterfaceDeclaration *ifaceNode, ir::ObjectExpression *objExpr, - ArenaVector &readonlyFields) + ir::TSInterfaceDeclaration *ifaceNode, ArenaVector &readonlyFields) { + FillClassBody(ctx, classBody, ifaceNode->Body()->Body(), readonlyFields); for (auto *extendedIface : ifaceNode->TsType()->AsETSObjectType()->Interfaces()) { auto extendedIfaceBody = extendedIface->GetDeclNode()->AsTSInterfaceDeclaration()->Body()->Body(); - FillClassBody(ctx, classBody, extendedIfaceBody, objExpr, readonlyFields, extendedIface); + FillClassBody(ctx, classBody, extendedIfaceBody, readonlyFields, extendedIface); } - - FillClassBody(ctx, classBody, ifaceNode->Body()->Body(), objExpr, readonlyFields); } -static checker::Type *GenerateAnonClassTypeFromInterface(public_lib::Context *ctx, - ir::TSInterfaceDeclaration *ifaceNode, - ir::ObjectExpression *objExpr) +static void GenerateAnonClassTypeFromInterface(public_lib::Context *ctx, ir::TSInterfaceDeclaration *ifaceNode) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); if (ifaceNode->GetAnonClass() != nullptr) { - return ifaceNode->GetAnonClass()->Definition()->TsType()->AsETSObjectType(); + return; } - auto classBodyBuilder = [ctx, checker, ifaceNode, objExpr](ArenaVector *classBody) { + auto classBodyBuilder = [ctx, checker, ifaceNode](ArenaVector *classBody) { if (ifaceNode->TsType() == nullptr) { ifaceNode->Check(checker); } ArenaVector readonlyFields(checker->Allocator()->Adapter()); - FillAnonClassBody(ctx, classBody, ifaceNode, objExpr, readonlyFields); + FillAnonClassBody(ctx, classBody, ifaceNode, readonlyFields); classBody->push_back(CreateAnonClassImplCtor(ctx, readonlyFields)); }; - auto anonClassName = GenName(checker->Allocator()); + auto originalName = std::string {ifaceNode->InternalName()}; + std::replace(originalName.begin(), originalName.end(), '.', '$'); + auto anonClassName = util::UString(originalName.append(OBJECT_LITERAL_SUFFIX), checker->Allocator()); auto *classDecl = checker->BuildClass(anonClassName.View(), classBodyBuilder); auto *classDef = classDecl->Definition(); auto *classType = classDef->TsType()->AsETSObjectType(); @@ -239,20 +240,17 @@ static checker::Type *GenerateAnonClassTypeFromInterface(public_lib::Context *ct checker->GetInterfacesOfClass(classType); ifaceNode->SetAnonClass(classDecl); - return classType; } -static checker::Type *GenerateAnonClassTypeFromAbstractClass(public_lib::Context *ctx, - ir::ClassDefinition *abstractClassNode, - ir::ObjectExpression *objExpr) +static void GenerateAnonClassTypeFromAbstractClass(public_lib::Context *ctx, ir::ClassDefinition *abstractClassNode) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); if (abstractClassNode->GetAnonClass() != nullptr) { - return abstractClassNode->GetAnonClass()->Definition()->TsType()->AsETSObjectType(); + return; } - auto classBodyBuilder = [checker, abstractClassNode, objExpr](ArenaVector *classBody) { + auto classBodyBuilder = [checker](ArenaVector *classBody) { checker::ETSChecker::ClassInitializerBuilder initBuilder = [checker]([[maybe_unused]] ArenaVector *statements, [[maybe_unused]] ArenaVector *params) { @@ -261,16 +259,11 @@ static checker::Type *GenerateAnonClassTypeFromAbstractClass(public_lib::Context auto ctor = checker->CreateClassInstanceInitializer(initBuilder); classBody->push_back(ctor); - - for (auto *it : abstractClassNode->Body()) { - if (it->IsMethodDefinition() && it->AsMethodDefinition()->IsAbstract()) { - checker->LogError(diagnostic::ABSTRACT_METH_IN_ABSTRACT_CLASS, {it->AsMethodDefinition()->Id()->Name()}, - objExpr->Start()); - } - } }; - auto anonClassName = GenName(checker->Allocator()); + auto originalName = std::string {abstractClassNode->InternalName()}; + std::replace(originalName.begin(), originalName.end(), '.', '$'); + auto anonClassName = util::UString(originalName.append(OBJECT_LITERAL_SUFFIX), checker->Allocator()); auto *classDecl = checker->BuildClass(anonClassName.View(), classBodyBuilder); auto *classDef = classDecl->Definition(); auto *classType = classDef->TsType()->AsETSObjectType(); @@ -291,23 +284,37 @@ static checker::Type *GenerateAnonClassTypeFromAbstractClass(public_lib::Context } abstractClassNode->SetAnonClass(classDecl); - classType->SetSuperType(objExpr->TsType()->AsETSObjectType()); - return classType; + classType->SetSuperType(abstractClassNode->TsType()->AsETSObjectType()); } static void HandleInterfaceLowering(public_lib::Context *ctx, ir::ObjectExpression *objExpr) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *targetType = objExpr->TsType(); checker->CheckObjectLiteralKeys(objExpr->Properties()); checker::Type *resultType; if (targetType->AsETSObjectType()->GetDeclNode()->IsTSInterfaceDeclaration()) { auto *ifaceNode = targetType->AsETSObjectType()->GetDeclNode()->AsTSInterfaceDeclaration(); - resultType = GenerateAnonClassTypeFromInterface(ctx, ifaceNode, objExpr); + if (ifaceNode->GetAnonClass() == nullptr) { + checker->LogError(diagnostic::INTERFACE_WITH_METHOD, {}, objExpr->Start()); + objExpr->SetTsType(checker->GlobalTypeError()); + return; + } + resultType = ifaceNode->GetAnonClass()->Definition()->TsType(); } else { ES2PANDA_ASSERT(targetType->AsETSObjectType()->GetDeclNode()->AsClassDefinition()->IsAbstract()); auto *abstractClassNode = targetType->AsETSObjectType()->GetDeclNode()->AsClassDefinition(); - resultType = GenerateAnonClassTypeFromAbstractClass(ctx, abstractClassNode, objExpr); + if (abstractClassNode->GetAnonClass() == nullptr) { + for (auto it : abstractClassNode->Body()) { + if (it->IsMethodDefinition() && it->AsMethodDefinition()->IsAbstract()) { + checker->LogError(diagnostic::ABSTRACT_METH_IN_ABSTRACT_CLASS, + {it->AsMethodDefinition()->Id()->Name()}, objExpr->Start()); + objExpr->SetTsType(checker->GlobalTypeError()); + return; + } + } + } + resultType = abstractClassNode->GetAnonClass()->Definition()->TsType(); } if (targetType->AsETSObjectType()->IsPartial()) { @@ -333,7 +340,50 @@ static void HandleInterfaceLowering(public_lib::Context *ctx, ir::ObjectExpressi objExpr->SetTsType(resultType); } -bool InterfaceObjectLiteralLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) +static bool CheckInterfaceShouldGenerateAnonClass(ir::TSInterfaceDeclaration *interfaceDecl) +{ + for (auto it : interfaceDecl->Body()->Body()) { + ES2PANDA_ASSERT(it->IsMethodDefinition()); + auto methodDef = it->AsMethodDefinition(); + if (!methodDef->Function()->IsGetter() && !methodDef->Function()->IsSetter()) { + return false; + } + } + + return true; +} + +static bool CheckAbstractClassShouldGenerateAnonClass(ir::ClassDefinition *classDef) +{ + auto constructorSigs = classDef->TsType()->AsETSObjectType()->ConstructSignatures(); + if (auto res = std::find_if(constructorSigs.cbegin(), constructorSigs.cend(), + [](checker::Signature *sig) -> bool { return sig->MinArgCount() == 0; }); + res == constructorSigs.cend()) { + return false; + } + for (auto it : classDef->Body()) { + if (it->IsMethodDefinition() && it->AsMethodDefinition()->IsAbstract()) { + return false; + } + } + + return true; +} + +static void TransfromInterfaceDecl(public_lib::Context *ctx, parser::Program *program) +{ + program->Ast()->IterateRecursivelyPostorder([ctx, program](ir::AstNode *ast) -> void { + if (ast->IsTSInterfaceDeclaration() && CheckInterfaceShouldGenerateAnonClass(ast->AsTSInterfaceDeclaration())) { + GenerateAnonClassTypeFromInterface(ctx, ast->AsTSInterfaceDeclaration()); + } else if (ast->IsClassDefinition() && ast != program->GlobalClass() && + ast->AsClassDefinition()->IsAbstract() && + CheckAbstractClassShouldGenerateAnonClass(ast->AsClassDefinition())) { + GenerateAnonClassTypeFromAbstractClass(ctx, ast->AsClassDefinition()); + } + }); +} + +static void TransfromInterfaceLiteral(public_lib::Context *ctx, parser::Program *program) { program->Ast()->IterateRecursivelyPostorder([ctx](ir::AstNode *ast) -> void { if (ast->IsObjectExpression() && (IsInterfaceType(ast->AsObjectExpression()->TsType()) || @@ -341,16 +391,45 @@ bool InterfaceObjectLiteralLowering::PerformForModule(public_lib::Context *ctx, HandleInterfaceLowering(ctx, ast->AsObjectExpression()); } }); - - return true; } -bool InterfaceObjectLiteralLowering::PostconditionForModule([[maybe_unused]] public_lib::Context *ctx, - const parser::Program *program) +bool InterfaceObjectLiteralLowering::Perform(public_lib::Context *ctx, parser::Program *program) { - return !program->Ast()->IsAnyChild([](const ir::AstNode *ast) -> bool { - return ast->IsObjectExpression() && (IsInterfaceType(ast->AsObjectExpression()->TsType()) || - IsAbstractClassType(ast->AsObjectExpression()->TsType())); - }); + auto *varbinder = program->VarBinder()->AsETSBinder(); + for (auto &[_, extPrograms] : program->ExternalSources()) { + (void)_; + for (auto *extProg : extPrograms) { + if (extProg->IsASTLowered()) { + continue; + } + auto *savedProgram = varbinder->Program(); + auto *savedRecordTable = varbinder->GetRecordTable(); + auto *savedTopScope = varbinder->TopScope(); + varbinder->ResetTopScope(extProg->GlobalScope()); + varbinder->SetRecordTable(varbinder->GetExternalRecordTable().at(extProg)); + varbinder->SetProgram(extProg); + TransfromInterfaceDecl(ctx, extProg); + varbinder->SetProgram(savedProgram); + varbinder->SetRecordTable(savedRecordTable); + varbinder->ResetTopScope(savedTopScope); + } + } + + TransfromInterfaceDecl(ctx, program); + + for (auto &[_, extPrograms] : program->ExternalSources()) { + (void)_; + for (auto *extProg : extPrograms) { + if (extProg->IsASTLowered()) { + continue; + } + TransfromInterfaceLiteral(ctx, extProg); + } + } + + TransfromInterfaceLiteral(ctx, program); + + return true; } + } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.h b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.h index b784b365c5c69277e571250079a6be99591e2e96..1ea67526170d82df2bcccb7f4156b6bc1ca51a90 100644 --- a/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.h +++ b/ets2panda/compiler/lowering/ets/interfaceObjectLiteralLowering.h @@ -20,11 +20,10 @@ namespace ark::es2panda::compiler { -class InterfaceObjectLiteralLowering : public PhaseForDeclarations { +class InterfaceObjectLiteralLowering : public Phase { public: std::string_view Name() const override; - bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; - bool PostconditionForModule(public_lib::Context *ctx, const parser::Program *program) override; + bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp index 01327be62a53b810db50636c2cbb203878a36a72..49cc3d075ff374dc14dffa95356dd3ec8e300bc1 100644 --- a/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp +++ b/ets2panda/compiler/lowering/ets/interfacePropertyDeclarations.cpp @@ -302,7 +302,7 @@ void InterfacePropertyDeclarationsPhase::UpdateClassProperties(checker::ETSCheck bool InterfacePropertyDeclarationsPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); varbinder::ETSBinder *const varbinder = ctx->parserProgram->VarBinder()->AsETSBinder(); ir::NodeTransformer handleInterfacePropertyDecl = [this, checker, varbinder](ir::AstNode *const ast) { diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index d43bd3f3b3d0d620558a7f658b7b3012371688ed..0aab5a0550a9c97cfad0fd9f582243b004beea79 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -71,7 +71,7 @@ static bool CheckIfNeedThis(ir::ArrowFunctionExpression *lambda, checker::ETSChe }); } -static size_t g_calleeCount = 0; +thread_local static size_t g_calleeCount = 0; // Make calleeCount behaviour predictable static void ResetCalleeCount() @@ -95,7 +95,7 @@ static std::pair Clon } auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *newScope = allocator->New(allocator, enclosingScope); auto newTypeParams = ArenaVector(allocator->Adapter()); @@ -157,8 +157,8 @@ ParamsAndVarMap CreateLambdaCalleeParameters(public_lib::Context *ctx, ir::Arrow varbinder::ParamScope *paramScope, checker::Substitution *substitution) { auto allocator = ctx->allocator; - auto checker = ctx->checker->AsETSChecker(); - auto varBinder = ctx->checker->VarBinder(); + auto checker = ctx->GetChecker()->AsETSChecker(); + auto varBinder = ctx->GetChecker()->VarBinder(); auto resParams = ArenaVector(allocator->Adapter()); auto varMap = ArenaMap(allocator->Adapter()); @@ -258,7 +258,7 @@ static ir::MethodDefinition *SetUpCalleeMethod(public_lib::Context *ctx, LambdaI varbinder::Scope *scopeForMethod) { auto *allocator = ctx->allocator; - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); auto *calleeClass = info->calleeClass; auto *funcScope = func->Scope(); @@ -297,9 +297,9 @@ static ir::MethodDefinition *SetUpCalleeMethod(public_lib::Context *ctx, LambdaI varbinder::BoundContext bctx {varBinder->GetRecordTable(), calleeClass->Definition(), true}; varBinder->ResolveReferencesForScopeWithContext(func, funcScope); - auto checkerCtx = checker::SavedCheckerContext(ctx->checker, checker::CheckerStatus::IN_CLASS, + auto checkerCtx = checker::SavedCheckerContext(ctx->GetChecker(), checker::CheckerStatus::IN_CLASS, calleeClass->Definition()->TsType()->AsETSObjectType()); - method->Check(ctx->checker->AsETSChecker()); + method->Check(ctx->GetChecker()->AsETSChecker()); return method; } @@ -309,8 +309,8 @@ static ir::MethodDefinition *CreateCalleeMethod(public_lib::Context *ctx, ir::Ar LambdaInfo const *info, CalleeMethodInfo const *cmInfo) { auto *allocator = ctx->allocator; - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); - auto *checker = ctx->checker->AsETSChecker(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *classScope = info->calleeClass->Definition()->Scope()->AsClassScope(); @@ -378,7 +378,7 @@ static ir::MethodDefinition *CreateCallee(public_lib::Context *ctx, ir::ArrowFun LambdaInfo const *info) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *body = lambda->Function()->Body()->AsBlockStatement(); auto calleeName = lambda->Function()->IsAsyncFunc() ? (util::UString {checker::ETSChecker::GetAsyncImplName(info->name), allocator}).View() @@ -417,7 +417,7 @@ static void CreateLambdaClassFields(public_lib::Context *ctx, ir::ClassDefinitio { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto props = ArenaVector(allocator->Adapter()); if (info->callReceiver != nullptr) { @@ -442,7 +442,7 @@ static void CreateLambdaClassConstructor(public_lib::Context *ctx, ir::ClassDefi { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto params = ArenaVector(allocator->Adapter()); auto makeParam = [checker, allocator, substitution, ¶ms](util::StringView name, checker::Type *type) { @@ -504,7 +504,7 @@ static ArenaVector CreateRestArgumentsArrayReall auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *restParameterType = lciInfo->lambdaSignature->RestVar()->TsType(); auto *restParameterSubstituteType = restParameterType->Substitute(checker->Relation(), lciInfo->substitution); @@ -557,7 +557,7 @@ static void CreateInvokeMethodRestParameter(public_lib::Context *ctx, LambdaClas ArenaVector *params) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *anyType = checker->GlobalETSNullishObjectType(); auto *restIdent = Gensym(allocator); @@ -585,7 +585,7 @@ static ArenaVector CreateCallArgumentsForLambdaClassInvoke(pub { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto callArguments = ArenaVector(allocator->Adapter()); for (auto *captured : *info->capturedVars) { @@ -660,7 +660,7 @@ static ir::BlockStatement *CreateLambdaClassInvokeBody(public_lib::Context *ctx, { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *anyType = checker->GlobalETSNullishObjectType(); auto *call = CreateCallForLambdaClassInvoke(ctx, info, lciInfo, wrapToObject); @@ -688,7 +688,7 @@ static void CreateLambdaClassInvokeMethod(public_lib::Context *ctx, LambdaInfo c bool wrapToObject) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *anyType = checker->GlobalETSNullishObjectType(); auto params = ArenaVector(allocator->Adapter()); @@ -751,7 +751,7 @@ static checker::ETSObjectType *FunctionTypeToLambdaProviderType(checker::ETSChec static void CorrectTheTrueThisForExtensionLambda(public_lib::Context *ctx, ir::ClassDeclaration *lambdaClass, size_t arity, bool hasRestParam) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *classScope = lambdaClass->Definition()->Scope(); ArenaVector invokeFuncsOfLambda(checker->Allocator()->Adapter()); auto invokeName = checker::FunctionalInterfaceInvokeName(arity, hasRestParam); @@ -791,8 +791,8 @@ static ir::ClassDeclaration *CreateEmptyLambdaClassDeclaration(public_lib::Conte { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *checker = ctx->GetChecker()->AsETSChecker(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); auto lambdaClassName = util::UString {std::string_view {"LambdaObject-"}, allocator}; lambdaClassName.Append(info->calleeClass->Definition()->Ident()->Name()).Append("$").Append(info->name); @@ -817,7 +817,7 @@ static ir::ClassDeclaration *CreateEmptyLambdaClassDeclaration(public_lib::Conte } auto *program = varBinder->GetRecordTable()->Program(); - program->Ast()->Statements().push_back(classDeclaration); + program->Ast()->AddStatement(classDeclaration); classDeclaration->SetParent(program->Ast()); return classDeclaration; @@ -826,8 +826,8 @@ static ir::ClassDeclaration *CreateEmptyLambdaClassDeclaration(public_lib::Conte static ir::ClassDeclaration *CreateLambdaClass(public_lib::Context *ctx, checker::ETSFunctionType *fntype, ir::MethodDefinition *callee, LambdaInfo const *info) { - auto *checker = ctx->checker->AsETSChecker(); - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *checker = ctx->GetChecker()->AsETSChecker(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); auto *oldTypeParams = (info->enclosingFunction != nullptr) ? info->enclosingFunction->TypeParams() : nullptr; auto [newTypeParams, subst0] = @@ -877,8 +877,8 @@ static ir::ETSNewClassInstanceExpression *CreateConstructorCall(public_lib::Cont LambdaInfo const *info) { auto *allocator = ctx->allocator; - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); - auto *checker = ctx->checker->AsETSChecker(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto args = ArenaVector(allocator->Adapter()); if (info->callReceiver != nullptr) { @@ -905,9 +905,9 @@ static ir::ETSNewClassInstanceExpression *CreateConstructorCall(public_lib::Cont auto lexScope = varbinder::LexicalScope::Enter(varBinder, nearestScope); varBinder->ResolveReferencesForScopeWithContext(newExpr, nearestScope); - auto checkerCtx = checker::SavedCheckerContext(ctx->checker, checker::CheckerStatus::IN_CLASS, + auto checkerCtx = checker::SavedCheckerContext(ctx->GetChecker(), checker::CheckerStatus::IN_CLASS, info->calleeClass->Definition()->TsType()->AsETSObjectType()); - auto scopeCtx = checker::ScopeContext(ctx->checker, nearestScope); + auto scopeCtx = checker::ScopeContext(ctx->GetChecker(), nearestScope); newExpr->Check(checker); return newExpr; @@ -916,7 +916,7 @@ static ir::ETSNewClassInstanceExpression *CreateConstructorCall(public_lib::Cont static ir::AstNode *ConvertLambda(public_lib::Context *ctx, ir::ArrowFunctionExpression *lambda) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); lambda->Check(checker); ES2PANDA_ASSERT(lambda->TsType()->IsETSFunctionType()); @@ -968,7 +968,7 @@ static ir::ScriptFunction *GetWrappingLambdaParentFunction(public_lib::Context * auto *callExpr = util::NodeAllocator::ForceSetParent(allocator, funcRef, std::move(callArgs), nullptr, false); ir::Statement *stmt; - if (signature->ReturnType() == ctx->checker->AsETSChecker()->GlobalVoidType()) { + if (signature->ReturnType() == ctx->GetChecker()->AsETSChecker()->GlobalVoidType()) { stmt = util::NodeAllocator::ForceSetParent(allocator, callExpr); } else { stmt = util::NodeAllocator::ForceSetParent(allocator, callExpr); @@ -982,7 +982,7 @@ static ir::ScriptFunction *GetWrappingLambdaParentFunction(public_lib::Context * static ir::ArrowFunctionExpression *CreateWrappingLambda(public_lib::Context *ctx, ir::Expression *funcRef) { auto *allocator = ctx->allocator; - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); ES2PANDA_ASSERT(funcRef->TsType()->IsETSArrowType()); auto signature = funcRef->TsType()->AsETSFunctionType()->ArrowSignature(); @@ -999,10 +999,10 @@ static ir::ArrowFunctionExpression *CreateWrappingLambda(public_lib::Context *ct auto [enclosingClass, _] = FindEnclosingClassAndFunction(parent); - auto checkerCtx = checker::SavedCheckerContext(ctx->checker, checker::CheckerStatus::IN_CLASS, + auto checkerCtx = checker::SavedCheckerContext(ctx->GetChecker(), checker::CheckerStatus::IN_CLASS, enclosingClass->Definition()->TsType()->AsETSObjectType()); - auto scopeCtx = checker::ScopeContext(ctx->checker, nearestScope); - lambda->Check(ctx->checker->AsETSChecker()); + auto scopeCtx = checker::ScopeContext(ctx->GetChecker(), nearestScope); + lambda->Check(ctx->GetChecker()->AsETSChecker()); return lambda; } @@ -1096,7 +1096,7 @@ static bool IsFunctionOrMethodCall(checker::ETSChecker *checker, ir::CallExpress static ir::AstNode *InsertInvokeCall(public_lib::Context *ctx, ir::CallExpression *call) { auto *allocator = ctx->allocator; - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *varBinder = checker->VarBinder()->AsETSBinder(); auto *oldCallee = call->Callee(); @@ -1112,6 +1112,7 @@ static ir::AstNode *InsertInvokeCall(public_lib::Context *ctx, ir::CallExpressio oldType->IsETSFunctionType() && oldType->AsETSFunctionType()->ArrowSignature()->HasRestParameter(); util::StringView invokeMethodName = util::UString {checker::FunctionalInterfaceInvokeName(arity, hasRestParam), allocator}.View(); + auto *prop = ifaceType->GetProperty(invokeMethodName, checker::PropertySearchFlags::SEARCH_INSTANCE_METHOD | checker::PropertySearchFlags::SEARCH_IN_INTERFACES); ES2PANDA_ASSERT(prop != nullptr); @@ -1215,7 +1216,7 @@ static ir::AstNode *LowerTypeNodeIfNeeded(public_lib::Context *ctx, ir::AstNode } auto allocator = ctx->allocator; - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); auto newTypeNode = allocator->New(type->AsETSFunctionType()->ArrowToFunctionalInterface(checker), allocator); @@ -1225,7 +1226,7 @@ static ir::AstNode *LowerTypeNodeIfNeeded(public_lib::Context *ctx, ir::AstNode bool LambdaConversionPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *varBinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); varbinder::RecordTableContext bctx {varBinder, program == ctx->parserProgram ? nullptr : program}; parser::SavedFormattingFileName savedFormattingName(ctx->parser->AsETSParser(), "lambda-conversion"); @@ -1243,7 +1244,7 @@ bool LambdaConversionPhase::PerformForModule(public_lib::Context *ctx, parser::P auto insertInvokeIfNeeded = [ctx](ir::AstNode *node) { if (node->IsCallExpression() && - !IsFunctionOrMethodCall(ctx->checker->AsETSChecker(), node->AsCallExpression()) && + !IsFunctionOrMethodCall(ctx->GetChecker()->AsETSChecker(), node->AsCallExpression()) && !IsRedirectingConstructorCall(node->AsCallExpression())) { return InsertInvokeCall(ctx, node->AsCallExpression()); } diff --git a/ets2panda/compiler/lowering/ets/localClassLowering.cpp b/ets2panda/compiler/lowering/ets/localClassLowering.cpp index 5153b0be11153d366b260cee6078f846923e0c3b..a2e671d396786258fb74726d71c5bb0453b264f3 100644 --- a/ets2panda/compiler/lowering/ets/localClassLowering.cpp +++ b/ets2panda/compiler/lowering/ets/localClassLowering.cpp @@ -82,7 +82,7 @@ void LocalClassConstructionPhase::CreateClassPropertiesForCapturedVariables( ArenaMap &variableMap, ArenaMap &propertyMap) { - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); size_t idx = 0; ArenaVector properties(ctx->allocator->Adapter()); for (auto var : capturedVars) { @@ -122,7 +122,7 @@ void LocalClassConstructionPhase::ModifyConstructorParameters( { auto *classType = classDef->TsType()->AsETSObjectType(); - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); for (auto *signature : classType->ConstructSignatures()) { LOG(DEBUG, ES2PANDA) << " - Modifying Constructor: " << signature->InternalName(); @@ -170,7 +170,7 @@ void LocalClassConstructionPhase::ModifyConstructorParameters( initStatements.push_back(initStatement); } if (body != nullptr && body->IsBlockStatement()) { - auto &statements = body->AsBlockStatement()->Statements(); + auto &statements = body->AsBlockStatement()->StatmentsForUpdates(); statements.insert(statements.begin(), initStatements.begin(), initStatements.end()); } } @@ -235,7 +235,7 @@ void LocalClassConstructionPhase::HandleLocalClass( bool LocalClassConstructionPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); ArenaUnorderedMap> capturedVarsMap { ctx->allocator->Adapter()}; diff --git a/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp b/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp index deefde6145b899278ad075e57cc06081c2aff4da..1f35c823d69cc6f96d0858d423cd5f91a0bb53ef 100644 --- a/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp +++ b/ets2panda/compiler/lowering/ets/objectIndexAccess.cpp @@ -107,7 +107,7 @@ bool ObjectIndexLowering::PerformForModule(public_lib::Context *ctx, parser::Pro { auto *const parser = ctx->parser->AsETSParser(); ES2PANDA_ASSERT(parser != nullptr); - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); ES2PANDA_ASSERT(checker != nullptr); program->Ast()->TransformChildrenRecursively( diff --git a/ets2panda/compiler/lowering/ets/objectIterator.cpp b/ets2panda/compiler/lowering/ets/objectIterator.cpp index b51283e9397bdd82b2d4b8b2f73507c3f15fea01..6c9642192a16d10f8f4a33a0dc9e013ca148db77 100644 --- a/ets2panda/compiler/lowering/ets/objectIterator.cpp +++ b/ets2panda/compiler/lowering/ets/objectIterator.cpp @@ -54,7 +54,7 @@ void ObjectIteratorLowering::TransferForOfLoopBody(ir::Statement *const forBody, ir::BlockStatement *const whileBody) const noexcept { ES2PANDA_ASSERT(forBody != nullptr && whileBody != nullptr); - auto &whileStatements = whileBody->Statements(); + auto &whileStatements = whileBody->StatmentsForUpdates(); // Currently while loop body consists of 2 statements: 'x = it.value!' and 'it = ci.next()' // We need to insert the body of original for-of-loop between them, change their parent and @@ -182,9 +182,9 @@ bool ObjectIteratorLowering::PerformForModule(public_lib::Context *ctx, parser:: { auto *const parser = ctx->parser->AsETSParser(); ES2PANDA_ASSERT(parser != nullptr); - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); ES2PANDA_ASSERT(checker != nullptr); - auto *const varbinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *const varbinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); ES2PANDA_ASSERT(varbinder != nullptr); auto hasIterator = [](checker::Type const *const exprType) -> bool { diff --git a/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp index fcad786898ef5d6cb2ad1aa43b247c1fa81ddcd6..af15fa49138ab09604389c7d289c73cad5609e22 100644 --- a/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/objectLiteralLowering.cpp @@ -250,9 +250,9 @@ static ir::AstNode *HandleObjectLiteralLowering(public_lib::Context *ctx, ir::Ob return objExpr; } - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); auto *const parser = ctx->parser->AsETSParser(); - auto *const varbinder = ctx->checker->VarBinder()->AsETSBinder(); + auto *const varbinder = ctx->GetChecker()->VarBinder()->AsETSBinder(); checker->AsETSChecker()->CheckObjectLiteralKeys(objExpr->Properties()); diff --git a/ets2panda/compiler/lowering/ets/opAssignment.cpp b/ets2panda/compiler/lowering/ets/opAssignment.cpp index f602b6281547f6b5bc8168d71376354f1bfa6317..38512d8ca561fbdd832cf3046aa10acf39789210 100644 --- a/ets2panda/compiler/lowering/ets/opAssignment.cpp +++ b/ets2panda/compiler/lowering/ets/opAssignment.cpp @@ -254,7 +254,7 @@ static ir::Expression *ConstructOpAssignmentResult(public_lib::Context *ctx, ir: { auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); const auto opEqual = assignment->OperatorType(); ES2PANDA_ASSERT(opEqual != lexer::TokenType::PUNCTUATOR_SUBSTITUTION); @@ -285,7 +285,7 @@ static ir::Expression *ConstructOpAssignmentResult(public_lib::Context *ctx, ir: ir::AstNode *HandleOpAssignment(public_lib::Context *ctx, ir::AssignmentExpression *assignment) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); if (assignment->TsType() == nullptr) { // hasn't been through checker return assignment; @@ -367,7 +367,7 @@ static ir::Expression *ConstructUpdateResult(public_lib::Context *ctx, ir::Updat auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); auto *argument = upd->Argument(); - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); ArgumentInfo argInfo {}; argInfo.objType = checker->GlobalVoidType(); @@ -408,7 +408,7 @@ static ir::Expression *ConstructUpdateResult(public_lib::Context *ctx, ir::Updat static ir::AstNode *HandleUpdate(public_lib::Context *ctx, ir::UpdateExpression *upd) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *const scope = NearestScope(upd); @@ -428,7 +428,7 @@ static ir::AstNode *HandleUpdate(public_lib::Context *ctx, ir::UpdateExpression return node; }, ""); - InitScopesPhaseETS::RunExternalNode(loweringResult, ctx->checker->VarBinder()); + InitScopesPhaseETS::RunExternalNode(loweringResult, ctx->GetChecker()->VarBinder()); checker->VarBinder()->AsETSBinder()->ResolveReferencesForScopeWithContext(loweringResult, NearestScope(loweringResult)); diff --git a/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp b/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp index 00d6d3f6a58f6618ad200ab6a929082e726a699d..f2aee03589906df9056c3948a96936b7007d48e7 100644 --- a/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp +++ b/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp @@ -37,7 +37,7 @@ static void TransformArguments(public_lib::Context *ctx, ir::Expression *callLik } ES2PANDA_ASSERT(arguments.size() >= signature->MinArgCount()); - auto const checker = ctx->checker->AsETSChecker(); + auto const checker = ctx->GetChecker()->AsETSChecker(); auto const allocator = ctx->allocator; size_t missing = signature->ArgCount() - arguments.size(); diff --git a/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp b/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp index 104d9083acb8e3f5f24af5f42694b0aeea709c08..f276856907c8a3e77d54aeff8700f158f6c9acfc 100644 --- a/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp +++ b/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp @@ -32,7 +32,7 @@ static void MergeExternalFilesIntoCompiledProgram(parser::Program *const program // Because same package files must be in one folder, relative path references in an external // source's import declaration certainly will be the same (and can be resolved) from the global program too - program->Ast()->Statements().emplace_back(stmt); + program->Ast()->AddStatement(stmt); } } } diff --git a/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp b/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp index 19f0157be76a2d10b33ba40927fd2fd7952aadff..ae2c9d283dc5692640322468b41e015621698127 100644 --- a/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp +++ b/ets2panda/compiler/lowering/ets/partialExportClassGen.cpp @@ -24,19 +24,23 @@ static void GeneratePartialDeclForExported(const public_lib::Context *const ctx, { // NOTE (mmartin): handle interfaces if (node->IsClassDeclaration()) { - ctx->checker->AsETSChecker()->CreatePartialType(node->AsClassDeclaration()->Definition()->TsType()); + ctx->GetChecker()->AsETSChecker()->CreatePartialType(node->AsClassDeclaration()->Definition()->TsType()); + } + if (node->IsTSInterfaceDeclaration()) { + ctx->GetChecker()->AsETSChecker()->CreatePartialType(node->AsTSInterfaceDeclaration()->TsType()); } } bool PartialExportClassGen::PerformForModule(public_lib::Context *const ctx, parser::Program *const program) { + program->Ast()->TransformChildrenRecursively( - [ctx, &program](ir::AstNode *const ast) { + [ctx, program](ir::AstNode *const ast) { if ((ast->IsClassDeclaration() || ast->IsTSInterfaceDeclaration()) && ast->IsExported()) { - auto *const savedProg = ctx->checker->VarBinder()->AsETSBinder()->Program(); - ctx->checker->VarBinder()->AsETSBinder()->SetProgram(program); + auto *const savedProg = ctx->GetChecker()->VarBinder()->AsETSBinder()->Program(); + ctx->GetChecker()->VarBinder()->AsETSBinder()->SetProgram(program); GeneratePartialDeclForExported(ctx, ast); - ctx->checker->VarBinder()->AsETSBinder()->SetProgram(savedProg); + ctx->GetChecker()->VarBinder()->AsETSBinder()->SetProgram(savedProg); } return ast; diff --git a/ets2panda/compiler/lowering/ets/partialExportClassGen.h b/ets2panda/compiler/lowering/ets/partialExportClassGen.h index dbe558e0e6512d4c9daf48012d787151c45a4213..05eb6cc69b32ba5695530c76fdab44588602006c 100644 --- a/ets2panda/compiler/lowering/ets/partialExportClassGen.h +++ b/ets2panda/compiler/lowering/ets/partialExportClassGen.h @@ -20,7 +20,7 @@ namespace ark::es2panda::compiler { -class PartialExportClassGen : public PhaseForBodies { +class PartialExportClassGen : public PhaseForDeclarations { public: std::string_view Name() const override { diff --git a/ets2panda/compiler/lowering/ets/promiseVoid.cpp b/ets2panda/compiler/lowering/ets/promiseVoid.cpp index fb2e729a989514a2cedcd3403fe3ba39a4a9409d..db0669a01b377d1a73936f90c35e20e34abc3ae4 100644 --- a/ets2panda/compiler/lowering/ets/promiseVoid.cpp +++ b/ets2panda/compiler/lowering/ets/promiseVoid.cpp @@ -119,7 +119,7 @@ using AstNodePtr = ir::AstNode *; bool PromiseVoidInferencePhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto genTypeLocation = [](ir::ScriptFunction *function) -> lexer::SourceRange { const auto ¶ms = function->Params(); diff --git a/ets2panda/compiler/lowering/ets/recordLowering.cpp b/ets2panda/compiler/lowering/ets/recordLowering.cpp index d8e2cfc9d7cf4d742a71f28c720d81526bb22309..e81ea329f757afdf1d305dd0af55bc54593ea313 100644 --- a/ets2panda/compiler/lowering/ets/recordLowering.cpp +++ b/ets2panda/compiler/lowering/ets/recordLowering.cpp @@ -92,18 +92,18 @@ void RecordLowering::CheckDuplicateKey(KeySetType &keySet, ir::ObjectExpression (number.IsDouble() && keySet.insert(number.GetDouble()).second)) { continue; } - ctx->checker->AsETSChecker()->LogError(diagnostic::OBJ_LIT_PROP_NAME_COLLISION, {}, expr->Start()); + ctx->GetChecker()->AsETSChecker()->LogError(diagnostic::OBJ_LIT_PROP_NAME_COLLISION, {}, expr->Start()); break; } case ir::AstNodeType::STRING_LITERAL: { if (keySet.insert(prop->Key()->AsStringLiteral()->Str()).second) { continue; } - ctx->checker->AsETSChecker()->LogError(diagnostic::OBJ_LIT_PROP_NAME_COLLISION, {}, expr->Start()); + ctx->GetChecker()->AsETSChecker()->LogError(diagnostic::OBJ_LIT_PROP_NAME_COLLISION, {}, expr->Start()); break; } case ir::AstNodeType::IDENTIFIER: { - ctx->checker->AsETSChecker()->LogError(diagnostic::OBJ_LIT_UNKNOWN_PROP, {}, expr->Start()); + ctx->GetChecker()->AsETSChecker()->LogError(diagnostic::OBJ_LIT_UNKNOWN_PROP, {}, expr->Start()); break; } default: { @@ -122,7 +122,7 @@ void RecordLowering::CheckLiteralsCompleteness(KeySetType &keySet, ir::ObjectExp } for (auto &ct : keyType->AsETSUnionType()->ConstituentTypes()) { if (ct->IsConstantType() && keySet.find(TypeToKey(ct)) == keySet.end()) { - ctx->checker->AsETSChecker()->LogError(diagnostic::OBJ_LIT_NOT_COVERING_UNION, {}, expr->Start()); + ctx->GetChecker()->AsETSChecker()->LogError(diagnostic::OBJ_LIT_NOT_COVERING_UNION, {}, expr->Start()); } } } @@ -154,7 +154,7 @@ ir::Statement *RecordLowering::CreateStatement(const std::string &src, ir::Expre ir::Expression *RecordLowering::UpdateObjectExpression(ir::ObjectExpression *expr, public_lib::Context *ctx) { - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); if (!expr->PreferredType()->IsETSObjectType()) { // Unexpected preferred type @@ -188,7 +188,7 @@ ir::Expression *RecordLowering::UpdateObjectExpression(ir::ObjectExpression *exp block->SetParent(expr->Parent()); // Run checks - InitScopesPhaseETS::RunExternalNode(block, ctx->checker->VarBinder()); + InitScopesPhaseETS::RunExternalNode(block, ctx->GetChecker()->VarBinder()); checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(block, NearestScope(block)); block->Check(checker); @@ -207,7 +207,7 @@ ir::Expression *RecordLowering::CreateBlockExpression(ir::ObjectExpression *expr * ... * map */ - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); // Initialize map with provided type arguments auto *ident = Gensym(checker->Allocator()); diff --git a/ets2panda/compiler/lowering/ets/restArgsLowering.cpp b/ets2panda/compiler/lowering/ets/restArgsLowering.cpp index 8726f60f085f22928e994a12db0d90467b090019..43731b15d2c1679c73eccdb4258aaf2b719e6c17 100644 --- a/ets2panda/compiler/lowering/ets/restArgsLowering.cpp +++ b/ets2panda/compiler/lowering/ets/restArgsLowering.cpp @@ -30,7 +30,7 @@ static ir::BlockExpression *CreateRestArgsBlockExpression(public_lib::Context *c { auto *allocator = context->allocator; auto *parser = context->parser->AsETSParser(); - auto *checker = context->checker->AsETSChecker(); + auto *checker = context->GetChecker()->AsETSChecker(); ArenaVector blockStatements(allocator->Adapter()); const auto arraySymbol = Gensym(allocator); @@ -89,7 +89,7 @@ static ir::Expression *CreateRestArgsArray(public_lib::Context *context, ArenaVe { auto *allocator = context->allocator; auto *parser = context->parser->AsETSParser(); - auto *checker = context->checker->AsETSChecker(); + auto *checker = context->GetChecker()->AsETSChecker(); // Handle single spread element case const size_t extraArgs = arguments.size() - signature->Params().size(); @@ -121,7 +121,7 @@ static ir::CallExpression *RebuildCallExpression(public_lib::Context *context, i checker::Signature *signature, ir::Expression *restArgsArray) { auto *allocator = context->allocator; - auto *varbinder = context->checker->VarBinder()->AsETSBinder(); + auto *varbinder = context->GetChecker()->VarBinder()->AsETSBinder(); ArenaVector newArgs(allocator->Adapter()); for (size_t i = 0; i < signature->Params().size(); ++i) { @@ -142,7 +142,7 @@ static ir::CallExpression *RebuildCallExpression(public_lib::Context *context, i auto *scope = NearestScope(newCall->Parent()); auto bscope = varbinder::LexicalScope::Enter(varbinder, scope); - CheckLoweredNode(context->checker->VarBinder()->AsETSBinder(), context->checker->AsETSChecker(), newCall); + CheckLoweredNode(context->GetChecker()->VarBinder()->AsETSBinder(), context->GetChecker()->AsETSChecker(), newCall); newCall->RemoveAstNodeFlags(ir::AstNodeFlags::RESIZABLE_REST); return newCall; } @@ -168,8 +168,9 @@ static ir::ETSNewClassInstanceExpression *RebuildNewClassInstanceExpression( newCall->AddModifier(originalCall->Modifiers()); newCall->AddBoxingUnboxingFlags(originalCall->GetBoxingUnboxingFlags()); auto *scope = NearestScope(newCall->Parent()); - auto bscope = varbinder::LexicalScope::Enter(context->checker->VarBinder()->AsETSBinder(), scope); - CheckLoweredNode(context->checker->VarBinder()->AsETSBinder(), context->checker->AsETSChecker(), newCall); + auto bscope = + varbinder::LexicalScope::Enter(context->GetChecker()->VarBinder()->AsETSBinder(), scope); + CheckLoweredNode(context->GetChecker()->VarBinder()->AsETSBinder(), context->GetChecker()->AsETSChecker(), newCall); return newCall; } diff --git a/ets2panda/compiler/lowering/ets/restTupleLowering.cpp b/ets2panda/compiler/lowering/ets/restTupleLowering.cpp index ea2e2ac25da3043b1f1acfeda3548d7caeee5ae1..d84515b49a32ea12fa836ce024d37d188d6ec28d 100644 --- a/ets2panda/compiler/lowering/ets/restTupleLowering.cpp +++ b/ets2panda/compiler/lowering/ets/restTupleLowering.cpp @@ -59,7 +59,7 @@ bool IsClassDefinitionWithTupleRest(ir::AstNode *node) ir::Expression *CreateMemberOrThisExpression(public_lib::Context *ctx, ir::Expression *funcExpr, ir::AstNode *definition) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; if (definition->IsConstructor()) { @@ -115,7 +115,7 @@ ir::TSTypeParameterInstantiation *CreateTypeParameterInstantiation(public_lib::C ir::CallExpression *CreateNewCallExpression(public_lib::Context *ctx, ir::Expression *funcExpr, ir::AstNode *definition, ir::TSAsExpression *asExpression) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; ArenaVector callArguments({}, checker->Allocator()->Adapter()); @@ -156,7 +156,7 @@ ir::CallExpression *CreateNewCallExpression(public_lib::Context *ctx, ir::Expres ArenaVector CreateFunctionRestParams(public_lib::Context *ctx, ir::AstNode *funcExpr) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; ArenaVector params {allocator->Adapter()}; @@ -207,7 +207,7 @@ ArenaVector MergeParams(public_lib::Context *ctx, ir::ArrayExpression *CreateArrayExpression(public_lib::Context *ctx, const ArenaVector &newRestParams) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; ArenaVector elementsInit(checker->Allocator()->Adapter()); @@ -253,7 +253,7 @@ ir::TSTypeParameterDeclaration *CreateNewParameterDeclaration(public_lib::Contex ir::ScriptFunction *CreateNewScriptFunction(public_lib::Context *ctx, ir::ScriptFunction *scriptFunc, ArenaVector newParams) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; ArenaVector statements(allocator->Adapter()); @@ -286,7 +286,7 @@ ir::ScriptFunction *CreateNewScriptFunction(public_lib::Context *ctx, ir::Script ir::VariableDeclaration *CreateNewVariableDeclaration(public_lib::Context *ctx, ir::ETSParameterExpression *restParam, ir::ArrayExpression *newTuple) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; util::StringView tupleIdentName = restParam->Ident()->Name(); @@ -308,7 +308,7 @@ ir::VariableDeclaration *CreateNewVariableDeclaration(public_lib::Context *ctx, ArenaVector CreateReturnOrExpressionStatement(public_lib::Context *ctx, ir::ScriptFunction *scriptFunc, ir::CallExpression *callExpr) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); ArenaVector statements(checker->Allocator()->Adapter()); @@ -326,7 +326,7 @@ ArenaVector CreateReturnOrExpressionStatement(public_lib::Conte ir::MethodDefinition *CreateNewMethodDefinition(public_lib::Context *ctx, ir::MethodDefinition *definition, ir::FunctionExpression *function) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; auto *methodKey = definition->AsMethodDefinition()->Key()->AsIdentifier()->Clone(allocator, nullptr); @@ -340,7 +340,7 @@ ir::MethodDefinition *CreateNewMethodDefinition(public_lib::Context *ctx, ir::Me void CreateNewMethod(public_lib::Context *ctx, ir::AstNode *node) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *allocator = ctx->allocator; for (auto definition : node->AsClassDefinition()->Body()) { diff --git a/ets2panda/compiler/lowering/ets/setJumpTarget.cpp b/ets2panda/compiler/lowering/ets/setJumpTarget.cpp index 95b29ec11e1053bd79416072d903908722f47265..46b9c961e7287c21d2bc6ece17607110318e202d 100644 --- a/ets2panda/compiler/lowering/ets/setJumpTarget.cpp +++ b/ets2panda/compiler/lowering/ets/setJumpTarget.cpp @@ -51,7 +51,7 @@ void SetJumpTargetPhase::FindJumpTarget(const public_lib::Context *ctx, ir::AstN var->SetScope(varbinder->GetScope()); label->SetVariable(var); decl->BindNode(label); - label->SetTsType(var->SetTsType(ctx->checker->GetGlobalTypesHolder()->GlobalTypeError())); + label->SetTsType(var->SetTsType(ctx->GetChecker()->GetGlobalTypesHolder()->GlobalTypeError())); } else if (var->Declaration()->IsLabelDecl()) { SetTarget(node, var->Declaration()->Node()); return; @@ -95,21 +95,13 @@ void SetJumpTargetPhase::FindJumpTarget(const public_lib::Context *ctx, ir::AstN SetTarget(node, nullptr); } -bool SetJumpTargetPhase::Perform(public_lib::Context *ctx, parser::Program *program) +bool SetJumpTargetPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - for (auto &[_, ext_programs] : program->ExternalSources()) { - (void)_; - for (auto *extProg : ext_programs) { - Perform(ctx, extProg); - } - } - program->Ast()->IterateRecursivelyPostorder([&](ir::AstNode *const node) -> void { if (node->IsBreakStatement() || node->IsContinueStatement()) { FindJumpTarget(ctx, node); } }); - return true; } diff --git a/ets2panda/compiler/lowering/ets/setJumpTarget.h b/ets2panda/compiler/lowering/ets/setJumpTarget.h index 79eb75efe431b4f827f6cc041e07fcd0956f7c76..ddef1ff51b4b92080a07176cb8c057324126907d 100644 --- a/ets2panda/compiler/lowering/ets/setJumpTarget.h +++ b/ets2panda/compiler/lowering/ets/setJumpTarget.h @@ -20,7 +20,7 @@ namespace ark::es2panda::compiler { -class SetJumpTargetPhase : public Phase { +class SetJumpTargetPhase : public PhaseForDeclarations { public: std::string_view Name() const override { @@ -28,7 +28,8 @@ public: } void FindJumpTarget(const public_lib::Context *ctx, ir::AstNode *const node); - bool Perform(public_lib::Context *ctx, parser::Program *program) override; + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; private: void LogError(const public_lib::Context *ctx, const diagnostic::DiagnosticKind &diagnostic, diff --git a/ets2panda/compiler/lowering/ets/spreadLowering.cpp b/ets2panda/compiler/lowering/ets/spreadLowering.cpp index 5ea7b5fb2a5fada9cfb3b6defba9f1481f284745..9debc1241df4b0fd26e1935a221de204a88f8238 100644 --- a/ets2panda/compiler/lowering/ets/spreadLowering.cpp +++ b/ets2panda/compiler/lowering/ets/spreadLowering.cpp @@ -82,7 +82,7 @@ static ir::Identifier *CreateNewArrayDeclareStatement(public_lib::Context *ctx, ArenaVector &statements, ir::Identifier *newArrayLengthId) { - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); auto *const allocator = ctx->allocator; auto *const parser = ctx->parser->AsETSParser(); ir::Identifier *newArrayId = Gensym(allocator); @@ -286,7 +286,8 @@ static void CreateNewArrayElementsAssignStatement(public_lib::Context *ctx, ir:: newTupleAssignmentStatements.cend()); } else { ir::Identifier *spreadArrIterator = Gensym(allocator); - checker::Type *arrayElementType = ctx->checker->AsETSChecker()->GetElementTypeOfArray(array->TsType()); + checker::Type *arrayElementType = + ctx->GetChecker()->AsETSChecker()->GetElementTypeOfArray(array->TsType()); statements.emplace_back(CreateElementsAssignStatementBySpreadArr( ctx, spArrIds[spArrIdx++], newArrayAndIndex, spreadArrIterator, arrayElementType)); } @@ -317,7 +318,7 @@ static void CreateNewArrayElementsAssignStatement(public_lib::Context *ctx, ir:: */ static ir::BlockExpression *CreateLoweredExpressionForArray(public_lib::Context *ctx, ir::ArrayExpression *array) { - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); auto *const parser = ctx->parser->AsETSParser(); auto *const allocator = ctx->allocator; ArenaVector statements(allocator->Adapter()); @@ -344,7 +345,7 @@ static ir::BlockExpression *CreateLoweredExpressionForArray(public_lib::Context */ static ir::BlockExpression *CreateLoweredExpressionForTuple(public_lib::Context *ctx, ir::ArrayExpression *array) { - auto *const checker = ctx->checker->AsETSChecker(); + auto *const checker = ctx->GetChecker()->AsETSChecker(); auto *const parser = ctx->parser->AsETSParser(); auto *const allocator = ctx->allocator; @@ -357,7 +358,7 @@ static ir::BlockExpression *CreateLoweredExpressionForTuple(public_lib::Context bool SpreadConstructionPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); varbinder::ETSBinder *const varbinder = checker->VarBinder()->AsETSBinder(); program->Ast()->TransformChildrenRecursively( diff --git a/ets2panda/compiler/lowering/ets/stringComparison.cpp b/ets2panda/compiler/lowering/ets/stringComparison.cpp index e7f0cb4f16fe5e16ef9f78fa01daad65ff108d95..d10fdb7b50a0e303bcae0730038064fa1497833a 100644 --- a/ets2panda/compiler/lowering/ets/stringComparison.cpp +++ b/ets2panda/compiler/lowering/ets/stringComparison.cpp @@ -78,7 +78,7 @@ void StringComparisonLowering::ProcessBinaryExpression(ir::BinaryExpression *exp // reset types is any, will re-run checker to set them once again properly expr->SetTsType(nullptr); - checker::ETSChecker *checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *checker = ctx->GetChecker()->AsETSChecker(); ArenaVector callArgs(checker->Allocator()->Adapter()); ir::Expression *accessor = nullptr; auto *zeroExpr = checker->AllocNode(util::StringView("0")); @@ -95,7 +95,7 @@ void StringComparisonLowering::ProcessBinaryExpression(ir::BinaryExpression *exp expr->SetRight(zeroExpr); auto *parent = expr->Parent(); - InitScopesPhaseETS::RunExternalNode(expr, ctx->checker->VarBinder()); + InitScopesPhaseETS::RunExternalNode(expr, ctx->GetChecker()->VarBinder()); checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(parent, NearestScope(parent)); if (parent->IsBinaryExpression() || parent->IsConditionalExpression()) { @@ -108,7 +108,7 @@ void StringComparisonLowering::ProcessBinaryExpression(ir::BinaryExpression *exp bool StringComparisonLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *checker = ctx->GetChecker()->AsETSChecker(); [[maybe_unused]] ArenaVector foundNodes(checker->Allocator()->Adapter()); // CC-OFFNXT(G.FMT.14-CPP) project code style program->Ast()->IterateRecursively([&foundNodes, this](ir::AstNode *ast) -> ir::AstNode * { diff --git a/ets2panda/compiler/lowering/ets/stringConstantsLowering.cpp b/ets2panda/compiler/lowering/ets/stringConstantsLowering.cpp index 30ec45a359a4921e0e39846b9eee903b7ac1bc20..5251fc8fb5061aef6602cd8ed504ab6f54769a72 100644 --- a/ets2panda/compiler/lowering/ets/stringConstantsLowering.cpp +++ b/ets2panda/compiler/lowering/ets/stringConstantsLowering.cpp @@ -34,15 +34,8 @@ static ir::AstNode *FoldConcat(public_lib::Context *ctx, ir::BinaryExpression *c return resNode; } -bool StringConstantsLowering::Perform(public_lib::Context *ctx, parser::Program *program) +bool StringConstantsLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - for (auto &[_, ext_programs] : program->ExternalSources()) { - (void)_; - for (auto *extProg : ext_programs) { - Perform(ctx, extProg); - } - } - program->Ast()->TransformChildrenRecursivelyPostorder( // CC-OFFNXT(G.FMT.14-CPP) project code style [ctx](ir::AstNode *const node) -> ir::AstNode * { @@ -56,7 +49,6 @@ bool StringConstantsLowering::Perform(public_lib::Context *ctx, parser::Program return node; }, Name()); - return true; } diff --git a/ets2panda/compiler/lowering/ets/stringConstantsLowering.h b/ets2panda/compiler/lowering/ets/stringConstantsLowering.h index d69fcb533944685b1ceed95600bd591e2964b724..fd45d74f1f54f6661400d7e4d1b0cf55e52a0146 100644 --- a/ets2panda/compiler/lowering/ets/stringConstantsLowering.h +++ b/ets2panda/compiler/lowering/ets/stringConstantsLowering.h @@ -20,10 +20,11 @@ namespace ark::es2panda::compiler { -class StringConstantsLowering : public Phase { +class StringConstantsLowering : public PhaseForDeclarations { public: std::string_view Name() const override; - bool Perform(public_lib::Context *ctx, parser::Program *program) override; + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/stringConstructorLowering.cpp b/ets2panda/compiler/lowering/ets/stringConstructorLowering.cpp index 9c7ef8d5338a6caf24f4df1a9fa33fabe79e6ae0..6b2d8c9c2234c3a2b91ae546762cf5598859adb5 100644 --- a/ets2panda/compiler/lowering/ets/stringConstructorLowering.cpp +++ b/ets2panda/compiler/lowering/ets/stringConstructorLowering.cpp @@ -48,7 +48,7 @@ static constexpr char const FORMAT_TO_STRING_EXPRESSION[] = "((@@E1 as Object).t ir::Expression *ReplaceStringConstructor(public_lib::Context *const ctx, ir::ETSNewClassInstanceExpression *newClassInstExpr) { - auto *checker = ctx->checker->AsETSChecker(); + auto *checker = ctx->GetChecker()->AsETSChecker(); auto *parser = ctx->parser->AsETSParser(); // Skip missing signatures diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp index 9b675c5de20031a6c515c23593679e6c4dbaf356..6fb5ddf1613f2533ea1e7a90f5a89f0df315471f 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp @@ -167,9 +167,7 @@ void GlobalClassHandler::MergeNamespace(ArenaVector &namespaces ES2PANDA_ASSERT(res->second->Annotations().empty()); res->second->SetAnnotations(std::move(ns->Annotations())); } - for (auto *statement : ns->Statements()) { - res->second->Statements().emplace_back(statement); - } + res->second->AddStatements(ns->Statements()); namespaces.erase(it); } else { nsMap.insert({ns->Ident()->Name(), ns}); @@ -178,10 +176,10 @@ void GlobalClassHandler::MergeNamespace(ArenaVector &namespaces } } -ArenaVector GlobalClassHandler::TransformNamespaces(ArenaVector &namespaces, - parser::Program *program) +ArenaVector GlobalClassHandler::TransformNamespaces(ArenaVector &namespaces, + parser::Program *program) { - ArenaVector classDecls {allocator_->Adapter()}; + ArenaVector classDecls {allocator_->Adapter()}; MergeNamespace(namespaces, program); for (auto ns : namespaces) { classDecls.emplace_back(TransformNamespace(ns, program)); @@ -197,7 +195,7 @@ ir::ClassDeclaration *GlobalClassHandler::TransformNamespace(ir::ETSModule *ns, ArenaVector immediateInitializers(allocator_->Adapter()); ArenaVector initializerBlock(allocator_->Adapter()); ArenaVector namespaces(allocator_->Adapter()); - auto &body = ns->Statements(); + auto &body = ns->StatmentsForUpdates(); for (auto *statement : body) { statement->Iterate([this](ir::AstNode *node) { AddStaticBlockToClass(node); }); } @@ -226,7 +224,7 @@ ir::ClassDeclaration *GlobalClassHandler::TransformNamespace(ir::ETSModule *ns, for (auto *cls : globalClasses) { globalClass->Body().emplace_back(cls); cls->SetParent(globalClass); - CollectNamespaceExportedClasses(cls->Definition()); + CollectNamespaceExportedClasses(cls->AsClassDeclaration()->Definition()); } // Add rest statement, such as type declaration @@ -241,10 +239,10 @@ ir::ClassDeclaration *GlobalClassHandler::TransformNamespace(ir::ETSModule *ns, void GlobalClassHandler::CollectProgramGlobalClasses(parser::Program *program, ArenaVector namespaces) { auto classDecls = TransformNamespaces(namespaces, program); + program->Ast()->AddStatements(classDecls); for (auto cls : classDecls) { - program->Ast()->Statements().push_back(cls); cls->SetParent(program->Ast()); - CollectNamespaceExportedClasses(cls->Definition()); + CollectNamespaceExportedClasses(cls->AsClassDeclaration()->Definition()); } } @@ -281,9 +279,9 @@ void GlobalClassHandler::SetupGlobalClass(const ArenaVector & ArenaVector initializerBlock(allocator_->Adapter()); ArenaVector namespaces(allocator_->Adapter()); - for (auto program : programs) { + for (auto const program : programs) { program->Ast()->IterateRecursively([this](ir::AstNode *node) { AddStaticBlockToClass(node); }); - auto &body = program->Ast()->Statements(); + auto &body = program->Ast()->StatmentsForUpdates(); auto stmts = CollectProgramGlobalStatements(body, globalClass, program->Ast()); auto end = std::remove_if(body.begin(), body.end(), [&namespaces](ir::AstNode *node) { if (node->IsETSModule() && node->AsETSModule()->IsNamespace()) { @@ -301,7 +299,7 @@ void GlobalClassHandler::SetupGlobalClass(const ArenaVector & program->SetGlobalClass(globalClass); } - globalProgram->Ast()->Statements().emplace_back(globalDecl); + globalProgram->Ast()->AddStatement(globalDecl); globalDecl->SetParent(globalProgram->Ast()); globalClass->SetGlobalInitialized(); CollectProgramGlobalClasses(globalProgram, namespaces); @@ -362,7 +360,7 @@ void GlobalClassHandler::AddInitializerBlockToStaticBlock(ir::ClassDefinition *g auto *blockBody = staticBlock->Function()->Body()->AsBlockStatement(); initializerStmts->SetParent(blockBody); - blockBody->Statements().emplace_back(initializerStmts); + blockBody->AddStatement(initializerStmts); } void GlobalClassHandler::AddInitCallToStaticBlock(ir::ClassDefinition *globalClass, ir::MethodDefinition *initMethod) @@ -383,7 +381,7 @@ void GlobalClassHandler::AddInitCallToStaticBlock(ir::ClassDefinition *globalCla auto *blockBody = staticBlock->Function()->Body()->AsBlockStatement(); auto exprStmt = NodeAllocator::Alloc(allocator_, callExpr); exprStmt->SetParent(blockBody); - blockBody->Statements().emplace_back(exprStmt); + blockBody->AddStatement(exprStmt); } ir::Identifier *GlobalClassHandler::RefIdent(const util::StringView &name) diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h index ae589327d1f9cafc16e003de9f9d4a35a80ae261..18d7fbbbc49fcd33eff7e4420dbd6b357badf017 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h @@ -62,8 +62,8 @@ private: ir::ClassDefinition *globalClass, bool isDeclare); void SetupInitializerBlock(parser::Program *program, ArenaVector> &&initializerBlock, ir::ClassDefinition *globalClass); - ArenaVector TransformNamespaces(ArenaVector &namespaces, - parser::Program *program); + ArenaVector TransformNamespaces(ArenaVector &namespaces, + parser::Program *program); ir::ClassDeclaration *CreateGlobalClass(const parser::Program *globalProgram); ir::ClassStaticBlock *CreateStaticBlock(ir::ClassDefinition *classDef); diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp index a75f467bfbe1d84a22a61a18fe22aaf2cb721e21..68282156008f38571a0dd51c480afefb0b7a044a 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp @@ -57,8 +57,10 @@ GlobalClassHandler::ModuleDependencies ImportExportDecls::HandleGlobalStmts(Aren if (!programs.empty()) { std::sort(programs.begin(), programs.end(), ProgramFileNameLessThan); } - for (const auto &program : programs) { - PreMergeNamespaces(program); + for (auto const &program : programs) { + if (!program->IsASTLowered()) { + PreMergeNamespaces(program); + } SavedImportExportDeclsContext savedContext(this, program); ProcessProgramStatements(program, program->Ast()->Statements(), moduleDependencies); VerifyCollectedExportName(program); @@ -367,7 +369,7 @@ void ImportExportDecls::PreMergeNamespaces(parser::Program *program) } ArenaVector namespaces(program->Allocator()->Adapter()); - auto &body = ast->AsETSModule()->Statements(); + auto &body = ast->AsETSModule()->StatmentsForUpdates(); auto originalSize = body.size(); auto end = std::remove_if(body.begin(), body.end(), [&namespaces](ir::AstNode *node) { if (node->IsETSModule() && node->AsETSModule()->IsNamespace()) { diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp index 448e32937d5cbac42eef1ce0f58f4d8521c16ad8..61e0a7f2c037807f0423860357d739392cc78adc 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp @@ -47,9 +47,32 @@ static bool CheckProgramSourcesConsistency(parser::Program *program) } return success; } +void TopLevelStatements::FetchCache([[maybe_unused]] public_lib::Context *ctx, + [[maybe_unused]] parser::Program *program) +{ + auto pVarBinder = program->VarBinder()->AsETSBinder(); + auto &reExportedImports = pVarBinder->ReExportImports(); + auto &aliasMap = pVarBinder->GetSelectiveExportAliasMultimap(); + for (auto &[package, extPrograms] : program->ExternalSources()) { + if (!extPrograms.front()->IsStdLib() && extPrograms.front()->IsASTLowered()) { + auto etsBinder = extPrograms.front()->VarBinder()->AsETSBinder(); + for (auto &it : etsBinder->ReExportImports()) { + if (it->GetTopStatement()->AsETSModule()->Program()->SourceFile().GetPath() != + program->SourceFile().GetPath()) { + reExportedImports.insert(it); + } + } + aliasMap.insert(etsBinder->GetSelectiveExportAliasMultimap().begin(), + etsBinder->GetSelectiveExportAliasMultimap().end()); + } + } +} bool TopLevelStatements::Perform(public_lib::Context *ctx, parser::Program *program) { + // if (program->IsASTLowered()) { + // FetchCache(ctx,program); + // } auto imports = ImportExportDecls(program->VarBinder()->AsETSBinder(), ctx->parser->AsETSParser()); imports.ParseDefaultSources(); if (!CheckProgramSourcesConsistency(program)) { @@ -58,8 +81,10 @@ bool TopLevelStatements::Perform(public_lib::Context *ctx, parser::Program *prog GlobalClassHandler globalClass(ctx->parser->AsETSParser(), program->Allocator()); for (auto &[package, extPrograms] : program->ExternalSources()) { - auto moduleDependencies = imports.HandleGlobalStmts(extPrograms); - globalClass.SetupGlobalClass(extPrograms, &moduleDependencies); + if (!extPrograms.front()->IsASTLowered()) { + auto moduleDependencies = imports.HandleGlobalStmts(extPrograms); + globalClass.SetupGlobalClass(extPrograms, &moduleDependencies); + } } ArenaVector mainModule(program->Allocator()->Adapter()); diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.h b/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.h index 0162d5492c90794d671feee11582a1252d4cdf7a..062a3890e49e1882883bf00dfad73e6c66fb1977 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.h +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/topLevelStmts.h @@ -40,6 +40,8 @@ public: return "TopLevelStatements"; } + void FetchCache([[maybe_unused]] public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) override; + bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; diff --git a/ets2panda/compiler/lowering/ets/typeFromLowering.cpp b/ets2panda/compiler/lowering/ets/typeFromLowering.cpp index 2ee7cc83d808ec0e86c4e6474c486d8a59ab8380..31f98cba357c1ae0c9bba133238f47b42d9818f9 100644 --- a/ets2panda/compiler/lowering/ets/typeFromLowering.cpp +++ b/ets2panda/compiler/lowering/ets/typeFromLowering.cpp @@ -116,7 +116,7 @@ std::string HandleTypeParameter(ir::Expression *param, checker::ETSChecker *chec ir::Expression *ReplaceTypeFrom(public_lib::Context *ctx, ir::CallExpression *ast) { auto parser = ctx->parser->AsETSParser(); - auto checker = ctx->checker->AsETSChecker(); + auto checker = ctx->GetChecker()->AsETSChecker(); auto *typeParams = ast->AsCallExpression()->TypeParams(); ES2PANDA_ASSERT(typeParams != nullptr && typeParams->Params().size() == 1); diff --git a/ets2panda/compiler/lowering/ets/unionLowering.cpp b/ets2panda/compiler/lowering/ets/unionLowering.cpp index 537de9bed0fa1dcc7a6f0811eb20c4f7a28981a4..972ed8b8edb58ae57c4a92da92130d06a74df2de 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/unionLowering.cpp @@ -24,7 +24,7 @@ namespace ark::es2panda::compiler { static constexpr std::string_view PREFIX = "$NamedAccessMeta-"; -static void ReplaceAll(std::string &str, std::string_view substr, std::string_view replacement) +void ReplaceAll(std::string &str, std::string_view substr, std::string_view replacement) { for (size_t pos = str.find(substr, 0); pos != std::string::npos; pos = str.find(substr, pos)) { str.replace(pos, substr.size(), replacement); @@ -32,7 +32,7 @@ static void ReplaceAll(std::string &str, std::string_view substr, std::string_vi } } -static std::string GetAccessClassName(const checker::ETSUnionType *unionType) +std::string GetAccessClassName(const checker::ETSUnionType *unionType) { std::stringstream ss; ss << PREFIX; @@ -44,8 +44,8 @@ static std::string GetAccessClassName(const checker::ETSUnionType *unionType) return res; } -static ir::ClassDefinition *GetUnionAccessClass(checker::ETSChecker *checker, varbinder::VarBinder *varbinder, - std::string const &name) +ir::ClassDefinition *GetUnionAccessClass(checker::ETSChecker *checker, varbinder::VarBinder *varbinder, + std::string const &name) { // Create the name for the synthetic class node if (auto foundVar = checker->Scope()->FindLocal(util::StringView(name), varbinder::ResolveBindingOptions::BINDINGS); @@ -71,7 +71,7 @@ static ir::ClassDefinition *GetUnionAccessClass(checker::ETSChecker *checker, va auto globalBlock = varbinder->Program()->Ast(); classDecl->SetParent(globalBlock); - globalBlock->Statements().push_back(classDecl); + globalBlock->AddStatement(classDecl); classDecl->Check(checker); return classDef; } @@ -124,8 +124,8 @@ static std::tuple CreateNamedA method->TsType()->AsETSFunctionType()->CallSignatures().front()}; } -static varbinder::LocalVariable *CreateNamedAccessProperty(checker::ETSChecker *checker, - varbinder::VarBinder *varbinder, ir::MemberExpression *expr) +varbinder::LocalVariable *CreateNamedAccessProperty(checker::ETSChecker *checker, varbinder::VarBinder *varbinder, + ir::MemberExpression *expr) { auto *const allocator = checker->Allocator(); auto unionType = checker->GetApparentType(checker->GetNonNullishType(expr->Object()->TsType()))->AsETSUnionType(); @@ -156,8 +156,8 @@ static varbinder::LocalVariable *CreateNamedAccessProperty(checker::ETSChecker * return var->AsLocalVariable(); } -static varbinder::LocalVariable *CreateNamedAccess(checker::ETSChecker *checker, varbinder::VarBinder *varbinder, - ir::MemberExpression *expr) +varbinder::LocalVariable *CreateNamedAccess(checker::ETSChecker *checker, varbinder::VarBinder *varbinder, + ir::MemberExpression *expr) { auto type = expr->TsType(); auto name = expr->Property()->AsIdentifier()->Name(); @@ -185,8 +185,7 @@ static varbinder::LocalVariable *CreateNamedAccess(checker::ETSChecker *checker, return CreateNamedAccessProperty(checker, varbinder, expr); } -static void HandleUnionPropertyAccess(checker::ETSChecker *checker, varbinder::VarBinder *vbind, - ir::MemberExpression *expr) +void HandleUnionPropertyAccess(checker::ETSChecker *checker, varbinder::VarBinder *vbind, ir::MemberExpression *expr) { if (expr->PropVar() != nullptr) { return; @@ -197,8 +196,8 @@ static void HandleUnionPropertyAccess(checker::ETSChecker *checker, varbinder::V ES2PANDA_ASSERT(expr->PropVar() != nullptr); } -static ir::TSAsExpression *GenAsExpression(checker::ETSChecker *checker, checker::Type *const opaqueType, - ir::Expression *const node, ir::AstNode *const parent) +ir::TSAsExpression *GenAsExpression(checker::ETSChecker *checker, checker::Type *const opaqueType, + ir::Expression *const node, ir::AstNode *const parent) { auto *const typeNode = checker->AllocNode(opaqueType, checker->Allocator()); auto *const asExpression = checker->AllocNode(node, typeNode, false); @@ -213,14 +212,14 @@ static ir::TSAsExpression *GenAsExpression(checker::ETSChecker *checker, checker * where (ref) is some unboxable type from union constituent types. * Finally, `(union) as (prim)` expression replaces union_node that came above. */ -static ir::TSAsExpression *UnionCastToPrimitive(checker::ETSChecker *checker, checker::ETSObjectType *unboxableRef, - checker::Type *unboxedPrim, ir::Expression *unionNode) +ir::TSAsExpression *UnionCastToPrimitive(checker::ETSChecker *checker, checker::ETSObjectType *unboxableRef, + checker::Type *unboxedPrim, ir::Expression *unionNode) { auto *const unionAsRefExpression = GenAsExpression(checker, unboxableRef, unionNode, nullptr); return GenAsExpression(checker, unboxedPrim, unionAsRefExpression, unionNode->Parent()); } -static ir::TSAsExpression *HandleUnionCastToPrimitive(checker::ETSChecker *checker, ir::TSAsExpression *expr) +ir::TSAsExpression *HandleUnionCastToPrimitive(checker::ETSChecker *checker, ir::TSAsExpression *expr) { auto *const unionType = expr->Expr()->TsType()->AsETSUnionType(); auto *sourceType = unionType->FindExactOrBoxedType(checker, expr->TsType()); @@ -257,7 +256,7 @@ static ir::TSAsExpression *HandleUnionCastToPrimitive(checker::ETSChecker *check bool UnionLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - checker::ETSChecker *checker = ctx->checker->AsETSChecker(); + checker::ETSChecker *checker = ctx->GetChecker()->AsETSChecker(); program->Ast()->TransformChildrenRecursively( // CC-OFFNXT(G.FMT.14-CPP) project code style @@ -286,7 +285,7 @@ bool UnionLowering::PerformForModule(public_lib::Context *ctx, parser::Program * bool UnionLowering::PostconditionForModule(public_lib::Context *ctx, const parser::Program *program) { - bool current = !program->Ast()->IsAnyChild([checker = ctx->checker->AsETSChecker()](ir::AstNode *ast) { + bool current = !program->Ast()->IsAnyChild([checker = ctx->GetChecker()->AsETSChecker()](ir::AstNode *ast) { if (!ast->IsMemberExpression() || ast->AsMemberExpression()->Object()->TsType() == nullptr) { return false; } diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index f64d8a43f2ad53ee0522d17673f428fe38c20a96..1e5c04d857ccbec7f6c0ab004283da0cc190c313 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -14,6 +14,8 @@ */ #include "phase.h" + +#include "util.h" #include "checker/checker.h" #include "compiler/lowering/checkerPhase.h" #include "compiler/lowering/ets/asyncMethodLowering.h" @@ -73,64 +75,53 @@ namespace ark::es2panda::compiler { static CheckerPhase g_checkerPhase; -static SetJumpTargetPhase g_setJumpTargetPhase; -static CFGBuilderPhase g_cfgBuilderPhase; -static ResolveIdentifiers g_resolveIdentifiers {}; -static AmbientLowering g_ambientLowering; -static ArrayLiteralLowering g_arrayLiteralLowering {}; -static BigIntLowering g_bigintLowering; -static StringConstructorLowering g_stringConstructorLowering; -static ConstantExpressionLowering g_constantExpressionLowering; -static ConstStringToCharLowering g_constStringToCharLowering; -static InterfacePropertyDeclarationsPhase g_interfacePropDeclPhase; // NOLINT(fuchsia-statically-constructed-objects) -static EnumLoweringPhase g_enumLoweringPhase; -static EnumPostCheckLoweringPhase g_enumPostCheckLoweringPhase; -static RestTupleConstructionPhase g_restTupleConstructionPhase; -static SpreadConstructionPhase g_spreadConstructionPhase; -static ExtensionAccessorPhase g_extensionAccessorPhase; -static ExpressionLambdaConstructionPhase g_expressionLambdaConstructionPhase; -static OpAssignmentLowering g_opAssignmentLowering; -static BoxingForLocals g_boxingForLocals; -static CapturedVariables g_capturedVariables {}; -static LambdaConversionPhase g_lambdaConversionPhase; -static ObjectIndexLowering g_objectIndexLowering; -static ObjectIteratorLowering g_objectIteratorLowering; -static ObjectLiteralLowering g_objectLiteralLowering; -static InterfaceObjectLiteralLowering g_interfaceObjectLiteralLowering; -static UnionLowering g_unionLowering; -static OptionalLowering g_optionalLowering; -static ExpandBracketsPhase g_expandBracketsPhase; -static PromiseVoidInferencePhase g_promiseVoidInferencePhase; -static RecordLowering g_recordLowering; -static DeclareOverloadLowering g_declareOverloadLowering; -static DefaultParametersLowering g_defaultParametersLowering; -static DefaultParametersInConstructorLowering g_defaultParametersInConstructorLowering; -static OptionalArgumentsLowering g_optionalArgumentsLowering; -static TopLevelStatements g_topLevelStatements; -static LocalClassConstructionPhase g_localClassLowering; -static StringComparisonLowering g_stringComparisonLowering; -static StringConstantsLowering g_stringConstantsLowering; -static PartialExportClassGen g_partialExportClassGen; -static PackageImplicitImport g_packageImplicitImport; -static GenericBridgesPhase g_genericBridgesLowering; -static BoxedTypeLowering g_boxedTypeLowering; -static AsyncMethodLowering g_asyncMethodLowering; -static TypeFromLowering g_typeFromLowering; -static ResizableArrayConvert g_resizableArrayConvert; -static RestArgsLowering g_restArgsLowering; -static InsertOptionalParametersAnnotation g_insertOptionalParametersAnnotation; -static PluginPhase g_pluginsAfterParse {"plugins-after-parse", ES2PANDA_STATE_PARSED, &util::Plugin::AfterParse}; -static PluginPhase g_pluginsAfterBind {"plugins-after-bind", ES2PANDA_STATE_BOUND, &util::Plugin::AfterBind}; -static PluginPhase g_pluginsAfterCheck {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}; -static PluginPhase g_pluginsAfterLowerings {"plugins-after-lowering", ES2PANDA_STATE_LOWERED, - &util::Plugin::AfterLowerings}; -// NOLINTBEGIN(fuchsia-statically-constructed-objects) +// static SetJumpTargetPhase g_setJumpTargetPhase; +// static CFGBuilderPhase g_cfgBuilderPhase; +// static ResolveIdentifiers g_resolveIdentifiers {}; +// static AmbientLowering g_ambientLowering; +// static ArrayLiteralLowering g_arrayLiteralLowering {}; +// static BigIntLowering g_bigintLowering; +// static StringConstructorLowering g_stringConstructorLowering; +// static ConstantExpressionLowering g_constantExpressionLowering; +// static ConstStringToCharLowering g_constStringToCharLowering; +// static InterfacePropertyDeclarationsPhase g_interfacePropDeclPhase; // +// NOLINT(fuchsia-statically-constructed-objects) static EnumLoweringPhase g_enumLoweringPhase; static +// EnumPostCheckLoweringPhase g_enumPostCheckLoweringPhase; static RestTupleConstructionPhase +// g_restTupleConstructionPhase; static SpreadConstructionPhase g_spreadConstructionPhase; static ExtensionAccessorPhase +// g_extensionAccessorPhase; static ExpressionLambdaConstructionPhase g_expressionLambdaConstructionPhase; static +// OpAssignmentLowering g_opAssignmentLowering; static BoxingForLocals g_boxingForLocals; static CapturedVariables +// g_capturedVariables {}; static LambdaConversionPhase g_lambdaConversionPhase; static ObjectIndexLowering +// g_objectIndexLowering; static ObjectIteratorLowering g_objectIteratorLowering; static ObjectLiteralLowering +// g_objectLiteralLowering; static InterfaceObjectLiteralLowering g_interfaceObjectLiteralLowering; static UnionLowering +// g_unionLowering; static OptionalLowering g_optionalLowering; static ExpandBracketsPhase g_expandBracketsPhase; static +// PromiseVoidInferencePhase g_promiseVoidInferencePhase; static RecordLowering g_recordLowering; static +// DeclareOverloadLowering g_declareOverloadLowering; static DefaultParametersLowering g_defaultParametersLowering; +// static DefaultParametersInConstructorLowering g_defaultParametersInConstructorLowering; +// static OptionalArgumentsLowering g_optionalArgumentsLowering; +// static TopLevelStatements g_topLevelStatements; +// static LocalClassConstructionPhase g_localClassLowering; +// static StringComparisonLowering g_stringComparisonLowering; +// static StringConstantsLowering g_stringConstantsLowering; +// static PartialExportClassGen g_partialExportClassGen; +// static PackageImplicitImport g_packageImplicitImport; +// static GenericBridgesPhase g_genericBridgesLowering; +// static BoxedTypeLowering g_boxedTypeLowering; +// static AsyncMethodLowering g_asyncMethodLowering; +// static TypeFromLowering g_typeFromLowering; +// static ResizableArrayConvert g_resizableArrayConvert; +// static RestArgsLowering g_restArgsLowering; +// static PluginPhase g_pluginsAfterParse {"plugins-after-parse", ES2PANDA_STATE_PARSED, &util::Plugin::AfterParse}; +// static PluginPhase g_pluginsAfterBind {"plugins-after-bind", ES2PANDA_STATE_BOUND, &util::Plugin::AfterBind}; +// static PluginPhase g_pluginsAfterCheck {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}; +// static PluginPhase g_pluginsAfterLowerings {"plugins-after-lowering", ES2PANDA_STATE_LOWERED, +// &util::Plugin::AfterLowerings}; +// // NOLINTBEGIN(fuchsia-statically-constructed-objects) static InitScopesPhaseETS g_initScopesPhaseEts; static InitScopesPhaseAS g_initScopesPhaseAs; static InitScopesPhaseTs g_initScopesPhaseTs; static InitScopesPhaseJs g_initScopesPhaseJs; -// NOLINTEND(fuchsia-statically-constructed-objects) -static DynamicImportLowering g_dynamicImportLowering; +// // NOLINTEND(fuchsia-statically-constructed-objects) +// static DynamicImportLowering g_dynamicImportLowering; // CC-OFFNXT(huge_method, G.FUN.01-CPP) long initialization list std::vector GetETSPhaseList() @@ -138,59 +129,60 @@ std::vector GetETSPhaseList() // clang-format off // NOLINTBEGIN return { - &g_pluginsAfterParse, - &g_stringConstantsLowering, - &g_packageImplicitImport, - &g_topLevelStatements, - &g_resizableArrayConvert, - &g_expressionLambdaConstructionPhase, - &g_insertOptionalParametersAnnotation, - &g_defaultParametersInConstructorLowering, - &g_defaultParametersLowering, - &g_ambientLowering, - &g_restTupleConstructionPhase, - &g_initScopesPhaseEts, - &g_optionalLowering, - &g_promiseVoidInferencePhase, - &g_interfacePropDeclPhase, - &g_constantExpressionLowering, - &g_enumLoweringPhase, - &g_resolveIdentifiers, - &g_pluginsAfterBind, - &g_capturedVariables, - &g_setJumpTargetPhase, - &g_cfgBuilderPhase, - &g_checkerPhase, // please DO NOT change order of these two phases: checkerPhase and pluginsAfterCheck - &g_pluginsAfterCheck, // pluginsAfterCheck has to go right after checkerPhase, nothing should be between them - &g_dynamicImportLowering, - &g_asyncMethodLowering, - &g_declareOverloadLowering, - &g_enumPostCheckLoweringPhase, - &g_spreadConstructionPhase, - &g_restArgsLowering, - &g_arrayLiteralLowering, - &g_bigintLowering, - &g_opAssignmentLowering, - &g_extensionAccessorPhase, - &g_constStringToCharLowering, - &g_boxingForLocals, - &g_recordLowering, - &g_boxedTypeLowering, - &g_objectIndexLowering, - &g_objectIteratorLowering, - &g_lambdaConversionPhase, - &g_unionLowering, - &g_expandBracketsPhase, - &g_localClassLowering, - &g_interfaceObjectLiteralLowering, - &g_objectLiteralLowering, - &g_stringConstructorLowering, - &g_stringComparisonLowering, - &g_partialExportClassGen, - &g_optionalArgumentsLowering, // #22952 could be moved to earlier phase - &g_genericBridgesLowering, - &g_typeFromLowering, - &g_pluginsAfterLowerings, // pluginsAfterLowerings has to come at the very end, nothing should go after it + new PluginPhase {"plugins-after-parse", ES2PANDA_STATE_PARSED, &util::Plugin::AfterParse}, + new StringConstantsLowering, + new PackageImplicitImport, + new TopLevelStatements, + new ResizableArrayConvert, + new ExpressionLambdaConstructionPhase, + new InsertOptionalParametersAnnotation, + new DefaultParametersInConstructorLowering, + new DefaultParametersLowering, + new AmbientLowering, + new RestTupleConstructionPhase, + new InitScopesPhaseETS, + new OptionalLowering, + new PromiseVoidInferencePhase, + new InterfacePropertyDeclarationsPhase, + new ConstantExpressionLowering, + new EnumLoweringPhase, + new ResolveIdentifiers, + new PluginPhase {"plugins-after-bind", ES2PANDA_STATE_BOUND, &util::Plugin::AfterBind}, + new CapturedVariables, + new SetJumpTargetPhase, + new CFGBuilderPhase, + new CheckerPhase, // please DO NOT change order of these two phases: checkerPhase and pluginsAfterCheck + new PluginPhase {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}, // pluginsAfterCheck has to go right after checkerPhase, nothing should be between them + new DynamicImportLowering, + new AsyncMethodLowering, + new DeclareOverloadLowering, + new EnumPostCheckLoweringPhase, + new SpreadConstructionPhase, + new RestArgsLowering, + new ArrayLiteralLowering, + new BigIntLowering, + new OpAssignmentLowering, + new ExtensionAccessorPhase, + new ConstStringToCharLowering, + new BoxingForLocals, + new RecordLowering, + new BoxedTypeLowering, + new ObjectIndexLowering, + new ObjectIteratorLowering, + new LambdaConversionPhase, + new UnionLowering, + new ExpandBracketsPhase, + new LocalClassConstructionPhase, + new PartialExportClassGen, + new InterfaceObjectLiteralLowering, // must be put after all classes are generated. + new ObjectLiteralLowering, + new StringConstructorLowering, + new StringComparisonLowering, + new OptionalArgumentsLowering, // #22952 could be moved to earlier phase + new GenericBridgesPhase, + new TypeFromLowering, + new PluginPhase{"plugins-after-lowering", ES2PANDA_STATE_LOWERED, + &util::Plugin::AfterLowerings}, // pluginsAfterLowerings has to come at the very end, nothing should go after it }; // NOLINTEND // clang-format on @@ -233,6 +225,16 @@ void SetPhaseManager(PhaseManager *phaseManager) g_phaseManager = phaseManager; } +void PhaseManager::Restart() +{ + prev_ = {0, INVALID_PHASE_ID}; + curr_ = {0, PARSER_PHASE_ID}; + next_ = PARSER_PHASE_ID + 1; + ES2PANDA_ASSERT(next_ == 0); + + SetPhaseManager(this); +} + bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) { SetPhaseManager(ctx->phaseManager); @@ -240,7 +242,7 @@ bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) #ifndef NDEBUG if (!Precondition(ctx, program)) { - ctx->checker->LogError(diagnostic::PRECOND_FAILED, {Name()}, lexer::SourcePosition {}); + ctx->GetChecker()->LogError(diagnostic::PRECOND_FAILED, {Name()}, lexer::SourcePosition {}); return false; } #endif @@ -251,7 +253,7 @@ bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) #ifndef NDEBUG if (!Postcondition(ctx, program)) { - ctx->checker->LogError(diagnostic::POSTCOND_FAILED, {Name()}, lexer::SourcePosition {}); + ctx->GetChecker()->LogError(diagnostic::POSTCOND_FAILED, {Name()}, lexer::SourcePosition {}); return false; } #endif @@ -264,6 +266,9 @@ bool PhaseForDeclarations::Precondition(public_lib::Context *ctx, const parser:: for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { + if (extProg->IsASTLowered()) { + continue; + } if (!Precondition(ctx, extProg)) { return false; } @@ -275,11 +280,14 @@ bool PhaseForDeclarations::Precondition(public_lib::Context *ctx, const parser:: bool PhaseForDeclarations::Perform(public_lib::Context *ctx, parser::Program *program) { + FetchCache(ctx, program); bool result = true; for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { - result &= Perform(ctx, extProg); + if (!extProg->IsASTLowered()) { + result &= Perform(ctx, extProg); + } } } @@ -292,6 +300,9 @@ bool PhaseForDeclarations::Postcondition(public_lib::Context *ctx, const parser: for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { + if (extProg->IsASTLowered()) { + continue; + } if (!Postcondition(ctx, extProg)) { return false; } @@ -326,12 +337,15 @@ bool PhaseForBodies::Precondition(public_lib::Context *ctx, const parser::Progra bool PhaseForBodies::Perform(public_lib::Context *ctx, parser::Program *program) { + FetchCache(ctx, program); bool result = true; if (ctx->config->options->GetCompilationMode() == CompilationMode::GEN_STD_LIB) { for (auto &[_, extPrograms] : program->ExternalSources()) { (void)_; for (auto *extProg : extPrograms) { - result &= Perform(ctx, extProg); + if (!extProg->IsASTLowered()) { + result &= Perform(ctx, extProg); + } } } } @@ -384,10 +398,26 @@ void PhaseManager::InitializePhases() int id = 0; for (auto phase : phases_) { + if (phase->Name() == "plugins-after-parse") { + jsPluginId1_ = id++; + } + // else if (phase->Name()=="plugins-after-bind") { + // JSPluginId2_ = id++; + if (phase->Name() == "plugins-after-check") { + jsPluginId3_ = id++; + } + // }else if (phase->Name()=="plugins-after-lowering") { + // JSPluginId4_ = id++; + // } phase->id_ = id++; } } +bool PhaseManager::InCheckerPhase() const +{ + return GetCurrentMinor() == jsPluginId3_-1; +} + std::vector PhaseManager::AllPhases() { ES2PANDA_ASSERT(IsInitialized()); @@ -397,21 +427,36 @@ std::vector PhaseManager::AllPhases() std::vector PhaseManager::RebindPhases() { ES2PANDA_ASSERT(IsInitialized()); - return { - &g_initScopesPhaseEts, - &g_resolveIdentifiers, - }; + return GetSubPhases({ScopesInitPhase::NAME, ResolveIdentifiers::NAME}); +} + +std::vector PhaseManager::GetSubPhases(const std::vector &phaseNames) +{ + std::vector phases; + for (auto &phaseName : phaseNames) { + for (auto phase : phases_) { + if (phase->Name() == phaseName) { + phases.emplace_back(phase); + } + } + } + return phases; } std::vector PhaseManager::RecheckPhases() { ES2PANDA_ASSERT(IsInitialized()); - return { - &g_initScopesPhaseEts, - &g_resolveIdentifiers, - &g_capturedVariables, - &g_checkerPhase, - }; + return GetSubPhases({ScopesInitPhase::NAME, ResolveIdentifiers::NAME, "CapturedVariables", CheckerPhase::NAME}); +} + +int32_t PhaseManager::GetCurrentMajor() const +{ + return curr_.major; +} + +int32_t PhaseManager::GetCurrentMinor() const +{ + return curr_.minor; } } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/phase.h b/ets2panda/compiler/lowering/phase.h index e1ff9c3885ed7db22ca7262b95cfa0c1f55f2ac2..4424cf635a5bae130904a7e277cb3bbae3dd51e9 100644 --- a/ets2panda/compiler/lowering/phase.h +++ b/ets2panda/compiler/lowering/phase.h @@ -18,12 +18,10 @@ #include "parser/program/program.h" #include "public/public.h" +#include "phase_id.h" namespace ark::es2panda::compiler { -constexpr int32_t INVALID_PHASE_ID = -2; -constexpr int32_t PARSER_PHASE_ID = -1; - class Phase { public: /* If Apply returns false, processing is stopped. */ @@ -31,6 +29,8 @@ public: virtual std::string_view Name() const = 0; + virtual void FetchCache([[maybe_unused]] public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) {} + virtual bool Precondition([[maybe_unused]] public_lib::Context *ctx, [[maybe_unused]] const parser::Program *program) { @@ -98,20 +98,30 @@ public: Restart(); } - int32_t PreviousPhaseId() const + PhaseId PreviousPhaseId() const { return prev_; } - int32_t CurrentPhaseId() const + PhaseId CurrentPhaseId() const { return curr_; } + bool InCheckerPhase() const; + + void SetCurrentPhaseId(int32_t phaseId) { + if (phaseId == curr_.minor) { + return; + } prev_ = curr_; - curr_ = phaseId; + + if (curr_.minor > phaseId) { + curr_.major++; + } + curr_.minor = phaseId; } ArenaAllocator *Allocator() const @@ -124,13 +134,7 @@ public: return allocator_ != nullptr && ext_ != ScriptExtension::INVALID; } - void Restart() - { - prev_ = INVALID_PHASE_ID; - curr_ = PARSER_PHASE_ID; - next_ = PARSER_PHASE_ID + 1; - ES2PANDA_ASSERT(next_ == 0); - } + void Restart(); Phase *NextPhase() { @@ -144,20 +148,41 @@ public: std::vector RebindPhases(); std::vector RecheckPhases(); + void SetCurrentPhaseIdToJSPlugin3() + { + GetPhaseManager()->SetCurrentPhaseId(jsPluginId3_); + } + + void SetCurrentPhaseIdToJSPlugin3Next() + { + GetPhaseManager()->SetCurrentPhaseId(0); + } + + void SetCurrentPhaseIdToJSPlugin1() + { + GetPhaseManager()->SetCurrentPhaseId(jsPluginId1_); + } + + int32_t GetCurrentMajor() const; + int32_t GetCurrentMinor() const; + + std::vector GetSubPhases(const std::vector &phaseNames); + private: void InitializePhases(); - int32_t prev_ {INVALID_PHASE_ID}; - int32_t curr_ {INVALID_PHASE_ID}; + PhaseId prev_ {0, INVALID_PHASE_ID}; + PhaseId curr_ {0, INVALID_PHASE_ID}; int32_t next_ {INVALID_PHASE_ID}; + int32_t jsPluginId1_ {0}; + // [[maybe_unused]] int32_t JSPluginId2_; + int32_t jsPluginId3_ {0}; + // [[maybe_unused]] int32_t JSPluginId4_; ArenaAllocator *allocator_ {nullptr}; ScriptExtension ext_ {ScriptExtension::INVALID}; std::vector phases_; }; -PhaseManager *GetPhaseManager(); -void SetPhaseManager(PhaseManager *phaseManager); - } // namespace ark::es2panda::compiler #endif diff --git a/ets2panda/compiler/lowering/phase_id.h b/ets2panda/compiler/lowering/phase_id.h new file mode 100644 index 0000000000000000000000000000000000000000..a3ba46c8f54a6df64e012af88a4801d8ce980a1a --- /dev/null +++ b/ets2panda/compiler/lowering/phase_id.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_LOWERING_PHASE_ID_H +#define ES2PANDA_COMPILER_LOWERING_PHASE_ID_H + +namespace ark::es2panda::compiler { + +constexpr int32_t INVALID_PHASE_ID = -2; +constexpr int32_t PARSER_PHASE_ID = -1; + +struct PhaseId { + int32_t major; // NOLINT(misc-non-private-member-variables-in-classes) + int32_t minor; // NOLINT(misc-non-private-member-variables-in-classes) + + bool operator<(const PhaseId &other) const + { + return major == other.major ? minor < other.minor : major < other.major; + } + + bool operator<=(const PhaseId &other) const + { + return major == other.major ? minor <= other.minor : major <= other.major; + } + + bool operator==(const PhaseId &other) const + { + return major == other.major && minor == other.minor; + } + + bool operator>=(const PhaseId &other) const + { + return major == other.major ? minor >= other.minor : major >= other.major; + } + + bool operator>(const PhaseId &other) const + { + return major == other.major ? minor > other.minor : major > other.major; + } +}; + +} // namespace ark::es2panda::compiler + +#endif diff --git a/ets2panda/compiler/lowering/plugin_phase.cpp b/ets2panda/compiler/lowering/plugin_phase.cpp index 14f72aa7f02c87f3130dabdcc180b4d5e946d523..daeade2f0de8b4e277b15877612d6b75fda56ff7 100644 --- a/ets2panda/compiler/lowering/plugin_phase.cpp +++ b/ets2panda/compiler/lowering/plugin_phase.cpp @@ -28,7 +28,7 @@ bool PluginPhase::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Pro for (auto &plugin : *(ctx->plugins)) { (plugin.*methodCall_)(reinterpret_cast(ctx)); if (ctx->state == ES2PANDA_STATE_ERROR) { - ctx->checker->LogTypeError(ctx->errorMessage, ctx->errorPos); + ctx->GetChecker()->LogTypeError(ctx->errorMessage, ctx->errorPos); return false; } } diff --git a/ets2panda/compiler/lowering/resolveIdentifiers.cpp b/ets2panda/compiler/lowering/resolveIdentifiers.cpp index cc13b62ce39ef58262e6e87fd129f0f71870af43..9aaed26a4b9921b03f21274c33536156587017ea 100644 --- a/ets2panda/compiler/lowering/resolveIdentifiers.cpp +++ b/ets2panda/compiler/lowering/resolveIdentifiers.cpp @@ -19,12 +19,36 @@ #include "util/options.h" namespace ark::es2panda::compiler { +void ResolveIdentifiers::FetchCache([[maybe_unused]] public_lib::Context *ctx, + [[maybe_unused]] parser::Program *program) +{ + auto pVarBinder = program->VarBinder()->AsETSBinder(); + auto &reExportedImports = pVarBinder->ReExportImports(); + auto &aliasMap = pVarBinder->GetSelectiveExportAliasMultimap(); + for (auto &[package, extPrograms] : program->ExternalSources()) { + if (!extPrograms.front()->IsStdLib() && extPrograms.front()->IsASTLowered()) { + auto etsBinder = extPrograms.front()->VarBinder()->AsETSBinder(); + for (auto &it : etsBinder->ReExportImports()) { + if (it->GetTopStatement()->AsETSModule()->Program()->SourceFile().GetPath() != + program->SourceFile().GetPath()) { + reExportedImports.insert(it); + } + } + aliasMap.insert(etsBinder->GetSelectiveExportAliasMultimap().begin(), + etsBinder->GetSelectiveExportAliasMultimap().end()); + } + } +} + bool ResolveIdentifiers::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) { + FetchCache(ctx, program); auto const *options = ctx->config->options; auto *varbinder = ctx->parserProgram->VarBinder()->AsETSBinder(); - if (options->IsDumpAst()) { + static bool ekko = true; + if (options->IsDumpAst() && ekko) { + ekko = false; std::cout << varbinder->Program()->Dump() << std::endl; } diff --git a/ets2panda/compiler/lowering/resolveIdentifiers.h b/ets2panda/compiler/lowering/resolveIdentifiers.h index 186363fbb0abe9113e21027fccee5dca44310441..7101940a3e0bfd94a343b90a7c360a8b32b066da 100644 --- a/ets2panda/compiler/lowering/resolveIdentifiers.h +++ b/ets2panda/compiler/lowering/resolveIdentifiers.h @@ -23,6 +23,8 @@ class ResolveIdentifiers : public Phase { public: static constexpr std::string_view NAME = "ResolveIdentifiers"; + void FetchCache(public_lib::Context *ctx, parser::Program *program) override; + std::string_view Name() const override { return "ResolveIdentifiers"; diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 7fd6b4a0bd3c33ba45c9dd0438dbdfe3a1dcd771..24165defb7bcb29d149c63038ce4388362d0d63d 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -834,6 +834,9 @@ void InitScopesPhaseETS::HandleProgram(parser::Program *program) (void)_; auto savedTopScope(program->VarBinder()->TopScope()); auto mainProg = prog_list.front(); + if (mainProg->IsASTLowered()) { + continue; + } mainProg->VarBinder()->InitTopScope(); AddGlobalToBinder(mainProg); BindScopeNode(mainProg->VarBinder()->GetScope(), mainProg->Ast()); diff --git a/ets2panda/compiler/lowering/util.cpp b/ets2panda/compiler/lowering/util.cpp index 013f4b7e6e4b003b316b17890dc0d464d6829167..129225ed079084b67489751423da8dfd55b88bcd 100644 --- a/ets2panda/compiler/lowering/util.cpp +++ b/ets2panda/compiler/lowering/util.cpp @@ -51,7 +51,7 @@ ir::Identifier *Gensym(ArenaAllocator *const allocator) util::UString GenName(ArenaAllocator *const allocator) { - static std::size_t gensymCounter = 0U; + thread_local static std::size_t gensymCounter = 0U; return util::UString {std::string(GENSYM_CORE) + std::to_string(++gensymCounter), allocator}; } @@ -69,7 +69,7 @@ ir::AstNode *RefineSourceRanges(ir::AstNode *node) }; auto const refine = [isDummyLoc](ir::AstNode *ast) { - if (isDummyLoc(ast->Range(), ast) && ast->Parent() != nullptr) { + if (ast->Parent() != nullptr && isDummyLoc(ast->Range(), ast)) { ast->SetRange(ast->Parent()->Range()); } }; @@ -157,7 +157,7 @@ static void ClearHelper(parser::Program *prog) { ResetGlobalClass(prog); // #24256 Should be removed when code refactoring on checker is done and no ast node allocated in checker. - auto &stmts = prog->Ast()->Statements(); + auto &stmts = prog->Ast()->StatmentsForUpdates(); // clang-format off stmts.erase(std::remove_if(stmts.begin(), stmts.end(), [](ir::AstNode *ast) -> bool { @@ -212,25 +212,49 @@ void Recheck(PhaseManager *phaseManager, varbinder::ETSBinder *varBinder, checke { RefineSourceRanges(node); if (node->IsProgram()) { + auto ctx = varBinder->GetContext(); + phaseManager->SetCurrentPhaseIdToJSPlugin3Next(); auto program = node->AsETSModule()->Program(); - if (program->IsPackage()) { - return; - } - + // if (program->IsPackage()) { + // return; + // } + auto newVarbinder = ctx->allocator->New(ctx->allocator); + newVarbinder->SetProgram(program); + newVarbinder->SetContext(ctx); + program->PushVarBinder(newVarbinder); + varBinder->CopyTo(newVarbinder); for (auto [_, program_list] : program->ExternalSources()) { for (auto prog : program_list) { - ClearHelper(prog); + if (!prog->IsASTLowered()) { + ClearHelper(prog); + prog->PushVarBinder(newVarbinder); + } } } ClearHelper(program); - varBinder->CleanUp(); - varBinder->GetContext()->checker->CleanUp(); + auto newChecker = ctx->allocator->New(*ctx->diagnosticEngine); + auto analyzer = ctx->allocator->New(newChecker); + + ctx->PushAnalyzer(analyzer); + newChecker->SetAnalyzer(analyzer); + newChecker->Initialize(newVarbinder); + ctx->PushChecker(newChecker); + for (auto [_, program_list] : program->ExternalSources()) { + if (auto prog = program_list.front(); prog->IsASTLowered()) { + newChecker->SetGlobalTypesHolder(prog->Checker()->GetGlobalTypesHolder()); + break; + } + } + + // varBinder->CleanUp(); + // varBinder->GetContext()->GetChecker()->CleanUp(); for (auto *phase : phaseManager->RecheckPhases()) { - phase->Apply(varBinder->GetContext(), program); + phase->Apply(ctx, program); } + phaseManager->SetCurrentPhaseIdToJSPlugin3(); return; } diff --git a/ets2panda/declgen_ets2ts/main.cpp b/ets2panda/declgen_ets2ts/main.cpp index 9dd3b1e3bc85f245778f9eb0d6d305eb6f77dd85..f8c441d441c2d1104275f4971c6c55cd2ea35bf5 100644 --- a/ets2panda/declgen_ets2ts/main.cpp +++ b/ets2panda/declgen_ets2ts/main.cpp @@ -93,7 +93,7 @@ static int Run(int argc, const char **argv) impl->CreateContextFromString(cfg, parserInputCStr, cfgImpl->options->SourceFileName().c_str()); auto *ctxImpl = reinterpret_cast(ctx); - auto *checker = reinterpret_cast(ctxImpl->checker); + auto *checker = reinterpret_cast(ctxImpl->GetChecker()); impl->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); diff --git a/ets2panda/driver/build_system/package.json b/ets2panda/driver/build_system/package.json index 597e3abe960a49076d13b6e22bf5cf5462c05391..1a245071469670b9503dc707e4274614c2ca276b 100644 --- a/ets2panda/driver/build_system/package.json +++ b/ets2panda/driver/build_system/package.json @@ -8,11 +8,9 @@ "clean": "rimraf dist", "build": "npm run clean && tsc", "build_debug": "npm run clean && tsc --sourceMap", - "mixed_hap:gen_decl": "npm run build && node ./dist/entry.js test/demo_mix_hap/build_config_decl.json", "mixed_hap:gen_abc": "node ./dist/entry.js test/demo_mix_hap/build_config.json", "mixed_hap:run": "npm run mixed_hap:gen_decl && npm run mixed_hap:gen_abc", - "demo_hap:gen_abc": "npm run build && node ./dist/entry.js test/demo_hap/build_config.json" }, "devDependencies": { @@ -21,7 +19,5 @@ "@tsconfig/recommended": "1.0.8", "rimraf": "6.0.1" }, - "dependencies": { - - } + "dependencies": {} } diff --git a/ets2panda/driver/build_system/src/build/base_mode.ts b/ets2panda/driver/build_system/src/build/base_mode.ts index 20ab3bd4bf06661fef8b670a6d881c9dab76dd73..d01f03c28195287048ac05f6150d31856ddbcb10 100644 --- a/ets2panda/driver/build_system/src/build/base_mode.ts +++ b/ets2panda/driver/build_system/src/build/base_mode.ts @@ -17,10 +17,17 @@ import * as os from 'os'; import * as path from 'path'; import * as fs from 'fs'; import * as child_process from 'child_process'; +import * as crypto from 'crypto'; + + import cluster, { Cluster, - Worker + Worker, } from 'cluster'; +import { + Worker as ThreadWorker, + workerData +} from 'worker_threads'; import { ABC_SUFFIX, ARKTSCONFIG_JSON_FILE, @@ -58,6 +65,8 @@ import { } from '../types'; import { ArkTSConfigGenerator } from './generate_arktsconfig'; import { SetupClusterOptions } from '../types'; +import { create } from 'domain'; +import { emitKeypressEvents } from 'readline'; export abstract class BaseMode { buildConfig: BuildConfig; entryFiles: Set; @@ -74,6 +83,7 @@ export abstract class BaseMode { moduleInfos: Map; mergedAbcFile: string; abcLinkerCmd: string[]; + depAnalyzerCmd: string[]; logger: Logger; isDebug: boolean; enableDeclgenEts2Ts: boolean; @@ -81,6 +91,7 @@ export abstract class BaseMode { declgenBridgeCodePath: string | undefined; hasMainModule: boolean; abcFiles: Set; + hasCleanWorker: boolean; constructor(buildConfig: BuildConfig) { this.buildConfig = buildConfig; @@ -106,8 +117,11 @@ export abstract class BaseMode { this.compileFiles = new Map(); this.mergedAbcFile = path.resolve(this.outputDir, MERGED_ABC_FILE); this.abcLinkerCmd = ['"' + this.buildConfig.abcLinkerPath + '"']; + this. depAnalyzerCmd = ['"' + this.buildConfig.depAnalyzerPath + '"']; + this.logger = Logger.getInstance(); + this.hasCleanWorker = false; } public declgen(fileInfo: CompileFileInfo): void { @@ -398,19 +412,21 @@ export abstract class BaseMode { let filePathInCache: string = path.join(this.cacheDir, moduleInfo.packageName, filePathFromModuleRoot); let abcFilePath: string = path.resolve(changeFileExtension(filePathInCache, ABC_SUFFIX)); this.abcFiles.add(abcFilePath); - if (!this.isFileChanged(file, abcFilePath)) { - return; - } + // if (!this.isFileChanged(file, abcFilePath)) { + // return; + // } let fileInfo: CompileFileInfo = { - filePath: file, + filePath: path.resolve(file), dependentFiles: [], abcFilePath: abcFilePath, arktsConfigFile: moduleInfo.arktsConfigFile, packageName: moduleInfo.packageName }; moduleInfo.compileFileInfos.push(fileInfo); - this.compileFiles.set(file, fileInfo); + console.log("[JIAKAI DEBUG] Module file: ", path.resolve(file)); + console.log("[JIAKAI DEBUG] Module fileInfo: ", fileInfo); + this.compileFiles.set(path.resolve(file), fileInfo); return; } const logData: LogData = LogDataFactory.newInstance( @@ -459,6 +475,7 @@ export abstract class BaseMode { this.mergeAbcFiles(); } + // -- runParallell code begins -- private terminateAllWorkers(): void { Object.values(cluster.workers || {}).forEach(worker => { worker?.kill(); @@ -547,7 +564,6 @@ export abstract class BaseMode { }); } - private getSerializableConfig(): Object { const ignoreList = [ 'compileFiles', @@ -582,4 +598,689 @@ export abstract class BaseMode { execArgv: execArgs, }); } + // -- runParallell code ends -- + + + // -- runConcurrent code begins -- + private getFileDependencies(output: string) { + let depAnalyzerCmd: string[] = this.depAnalyzerCmd; + + // let depAnalyzerPath: string = path.resolve( + // this.buildSdkPath, + // 'build-tools', + // 'ets2panda', + // 'bin', + // 'dependency_analyzer.exe' + // ); + // depAnalyzerCmd.push(`"${depAnalyzerPath}"`); + + // let entryFiles: string[] = ["/home/jiakai/developtools/ace_ets2bundle/arkui-plugins/test/demo/localtest/entry/new.ets"]; + let entryFiles: string[] = this.buildConfig.entryFiles || []; + + // entryFiles.forEach((file: string) => { + // depAnalyzerCmd.push(file); + // }); + + let depInputContent = ''; + let depInputFile = path.join(this.cacheDir, 'depInput.txt'); + entryFiles.forEach((file: string) => { + depInputContent += file + os.EOL; + }); + fs.writeFileSync(depInputFile, depInputContent); + this.depAnalyzerCmd.push('--'); + this.depAnalyzerCmd.push('@' + '"' + depInputFile + '"'); + + let outputFile: string = output; + depAnalyzerCmd.push(`--output=${outputFile}`); + + let arktsConfigFile: string = path.resolve(this.moduleInfos.get("entry")?.arktsConfigFile!); + depAnalyzerCmd.push(`--arktsconfig=${arktsConfigFile}`); + + let depAnalyzerCmdStr: string = depAnalyzerCmd.join(' '); + if (isMac()) { + const loadLibrary = 'DYLD_LIBRARY_PATH=' + '"' + process.env.DYLD_LIBRARY_PATH + '"'; + depAnalyzerCmdStr = loadLibrary + ' ' + depAnalyzerCmdStr; + } + this.logger.printInfo(depAnalyzerCmdStr); + ensurePathExists(outputFile); + + try { + child_process.execSync(depAnalyzerCmdStr).toString(); + } catch (error) { + if (error instanceof Error) { + const logData: LogData = LogDataFactory.newInstance( + ErrorCode.BUILDSYSTEM_LINK_ABC_FAIL, + 'get files dependencies failed.', + error.message + ); + this.logger.printError(logData); + } + } + } + + private findCircularDependencies(files: Record): Map { + const visited = new Set(); + const recursionStack = new Set(); + const cycleGroups = new Map(); + + function dfs(nodeId: string, path: string[]): void { + if (recursionStack.has(nodeId)) { + const cycleStart = path.indexOf(nodeId); + const cycleIds = path.slice(cycleStart).concat(nodeId); + + const sortedIds = [...new Set(cycleIds)].sort(); + const cycleHash = createHash(sortedIds.join('|')); + + if (!cycleGroups.has(cycleHash)) { + cycleGroups.set(cycleHash, sortedIds); + } + return; + } + + if (visited.has(nodeId)) return; + + visited.add(nodeId); + recursionStack.add(nodeId); + path.push(nodeId); + + const dependencies = files[nodeId] || []; + for (const depId of dependencies) { + dfs(depId, [...path]); + } + + recursionStack.delete(nodeId); + } + + Object.entries(files).forEach(([key, value]) => { + if (!visited.has(key)) { + dfs(key, []); + } + }); + + return cycleGroups; + } + + private concatCycleGroups(cycleGroups: Map): Map { + const generateCycleHash = (cycles: string[]): string => { + const sortedFiles = cycles.sort(); + return createHash(sortedFiles.join('|')); + } + + // 创建一个文件到所属环的映射 + const fileToCycles = new Map>(); + + // 第一步:建立文件到环的映射关系 + for (const [cycleHash, cycleGroup] of cycleGroups) { + for (const file of cycleGroup) { + if (!fileToCycles.has(file)) { + fileToCycles.set(file, new Set()); + } + fileToCycles.get(file)!.add(cycleHash); + } + } + + // 第二步:找出需要合并的环组 + const merged = new Map(); + const visitedCycles = new Set(); + + for (const [cycleHash, cycleGroup] of cycleGroups) { + if (visitedCycles.has(cycleHash)) continue; + + // 初始化合并后的环 + const mergedCycle = new Set([...cycleGroup]); + const cyclesToMerge = new Set([cycleHash]); + visitedCycles.add(cycleHash); + + // 使用队列处理需要合并的环 + const queue: string[] = [cycleHash]; + + while (queue.length > 0) { + const currentCycle = queue.shift()!; + + // 检查当前环中所有文件关联的其他环 + for (const file of cycleGroups.get(currentCycle)!) { + for (const relatedCycle of fileToCycles.get(file) || []) { + if (!visitedCycles.has(relatedCycle)) { + visitedCycles.add(relatedCycle); + cyclesToMerge.add(relatedCycle); + queue.push(relatedCycle); + + // 将关联环中的文件合并进来 + for (const f of cycleGroups.get(relatedCycle)!) { + mergedCycle.add(f); + } + } + } + } + } + + // 生成新的环哈希(使用合并后所有文件名的排序哈希) + const newHash = generateCycleHash(Array.from(mergedCycle)); + merged.set(newHash, Array.from(mergedCycle)); + } + + return merged; + } + + private findStronglyConnectedComponents(graph: FileDepsInfo): Map> { + // 1. 构建邻接表和反向邻接表 + const adjacencyList: Record = {}; + const reverseAdjacencyList: Record = {}; + const allNodes = new Set(); + + // 初始化所有节点 + for (const node in graph.dependencies) { + allNodes.add(node); + graph.dependencies[node].forEach(dep => allNodes.add(dep)); + } + for (const node in graph.dependants) { + allNodes.add(node); + graph.dependants[node].forEach(dep => allNodes.add(dep)); + } + + // 构建邻接表 + Array.from(allNodes).forEach(node => { + adjacencyList[node] = graph.dependencies[node] || []; + reverseAdjacencyList[node] = graph.dependants[node] || []; + }); + + // 2. 第一次DFS计算finishing order + const visited = new Set(); + const order: string[] = []; + + function dfs(node: string) { + visited.add(node); + for (const neighbor of adjacencyList[node]) { + if (!visited.has(neighbor)) { + dfs(neighbor); + } + } + order.push(node); + } + + Array.from(allNodes).forEach(node => { + if (!visited.has(node)) { + dfs(node); + } + }); + + // 3. 第二次DFS在反向图上找SCCs + visited.clear(); + const components = new Map>(); + + function reverseDfs(node: string, component: Set) { + visited.add(node); + component.add(node); + for (const neighbor of reverseAdjacencyList[node]) { + if (!visited.has(neighbor)) { + reverseDfs(neighbor, component); + } + } + } + + for (let i = order.length - 1; i >= 0; i--) { + const node = order[i]; + if (!visited.has(node)) { + const component = new Set(); + reverseDfs(node, component); + // 生成排序后的哈希key + if (component.size > 1) { + const sortedFiles = Array.from(component).sort(); + const hashKey = createHash(sortedFiles.join('|')); + components.set(hashKey, component); + } + + } + } + + return components; + } + + + private getJobDependencies(fileDeps: string[], cycleFiles: Map): Set { + let depJobList: Set = new Set(); + fileDeps.forEach((file) => { + if (!cycleFiles.has(file)) { + depJobList.add('0' + file); + } else { + cycleFiles.get(file)?.forEach((f) => { + depJobList.add(f); + }); + } + }); + + return depJobList; + } + + private getJobDependants(fileDeps: string[], cycleFiles: Map): Set { + let depJobList: Set = new Set(); + fileDeps.forEach((file) => { + if (!file.endsWith(DECL_ETS_SUFFIX)) { + depJobList.add('1' + file); + } + if (cycleFiles.has(file)) { + cycleFiles.get(file)?.forEach((f) => { + depJobList.add(f); + }); + } else { + depJobList.add('0' + file); + } + }); + + return depJobList; + } + + private collectCompileJobs(jobs: Record): void { + let fileDepsInfoJson: string = path.resolve(this.cacheDir, "file_dependencies.json"); + this.getFileDependencies(fileDepsInfoJson); + const data = fs.readFileSync(fileDepsInfoJson, 'utf-8'); + let fileDepsInfo: FileDepsInfo = JSON.parse(data) as FileDepsInfo; + + Object.keys(fileDepsInfo.dependants).forEach((file) => { + if (!(file in fileDepsInfo.dependencies)) { + fileDepsInfo.dependencies[file] = []; + } + }); + + console.log("fileDepsInfo: ", fileDepsInfo); + + // const _cycleGroups = this.findCircularDependencies(fileDepsInfo.dependencies); + // console.log("cycle dependents: ", _cycleGroups); + // const cycleGroups = this.concatCycleGroups(_cycleGroups); + // console.log("merged cycle dependents: ", cycleGroups); + + // // key: fileName, value: cycleIds in all cycles + // let cycleFiles: Map = new Map(); + + // // key: cycleId, value: files in this cycle + // cycleGroups.forEach((value: string[], key: string) => { + // value.forEach((file) => { + // const cycleGrps = cycleFiles.has(file) ? [...new Set([...cycleFiles.get(file)!, key])] : [key]; + // cycleFiles.set(file, cycleGrps); + // }); + + // }); + + // console.log('cycle files: ', cycleFiles); + + const cycleGroups = this.findStronglyConnectedComponents(fileDepsInfo); + console.log("cycle dependents: ", cycleGroups); + let cycleFiles: Map = new Map(); + cycleGroups.forEach((value: Set, key: string) => { + value.forEach((file) => { + cycleFiles.set(file, [key]); + }); + }); + + Object.entries(fileDepsInfo.dependencies).forEach(([key, value]) => { + let dependencies = this.getJobDependencies(value, cycleFiles); + + if (!key.endsWith(DECL_ETS_SUFFIX)) { + let abcJobId: string = '1' + key; + jobs[abcJobId] = { + id: abcJobId, + isDeclFile: false, + isInCycle: cycleFiles.has(key), + isAbcJob: true, + fileList: [key], + dependencies: Array.from(dependencies), // 依赖external program + dependants: [] + }; + } + + if (cycleFiles.has(key)) { + const externalProgramJobIds = cycleFiles.get(key)!; + externalProgramJobIds.forEach((id) => { + // let fileList: string[] = cycleGroups.get(id)!; + let fileList: string[] = Array.from(cycleGroups.get(id)!); + this.createExternalProgramJob(id, fileList, jobs, dependencies, true); + }); + } else { + const id = '0' + key; + let fileList: string[] = [key]; + this.createExternalProgramJob(id, fileList, jobs, dependencies); + } + + // let externalProgramJobId = cycleFiles.has(key) ? cycleFiles.get(key)! : '0' + key; + // console.log('[JIAKAI DEBUG] externalProgramJobId: ', externalProgramJobId); + + // let fileList: string[] = cycleFiles.has(key) ? cycleGroups.get(cycleFiles.get(key)!)! : [key]; + // if (dependencies.has(externalProgramJobId)) { + // dependencies.delete(externalProgramJobId); + // } + // jobs[externalProgramJobId] = { + // id: externalProgramJobId, + // fileList, + // isDeclFile: true, + // isInCycle: cycleFiles.has(key), + // isAbcJob: false, + // dependencies: Array.from(dependencies), // 依赖external program + // dependants: [] + // }; + + if (key.endsWith(DECL_ETS_SUFFIX)) { + let fileInfo: CompileFileInfo = { + filePath: key, + dependentFiles: [], + abcFilePath: '', + arktsConfigFile: this.moduleInfos.get(this.packageName)!.arktsConfigFile, + packageName: this.moduleInfos.get(this.packageName)!.packageName + }; + + if (!this.compileFiles.has(key)) { + this.compileFiles.set(key, fileInfo); + } + } + }); + + Object.entries(fileDepsInfo.dependants).forEach(([key, value]) => { + let dependants = this.getJobDependants(value, cycleFiles); + + if (cycleFiles.has(key)) { + const externalProgramJobIds = cycleFiles.get(key)!; + externalProgramJobIds.forEach((id) => { + jobs[id].dependants.forEach(dep => { + dependants.add(dep) + }) + if (dependants.has(id)) { + dependants.delete(id); + } + + jobs[id].dependants = Array.from(dependants); + }); + } else { + const id = '0' + key; + jobs[id].dependants.forEach(dep => { + dependants.add(dep) + }) + if (dependants.has(id)) { + dependants.delete(id); + } + jobs[id].dependants = Array.from(dependants); + } + + // let externalProgramJobId = cycleFiles.has(key) ? cycleFiles.get(key)! : '0' + key; + // if (dependants.has(externalProgramJobId)) { + // dependants.delete(externalProgramJobId); + // } + // jobs[externalProgramJobId].dependants.push(...Array.from(dependants)); + }); + + console.log("-------- jobs: ", jobs); + + } + + private createExternalProgramJob(id: string, fileList: string[], jobs: Record, dependencies: Set, isInCycle?: boolean) { + if (dependencies.has(id)) { + dependencies.delete(id); + } + + // TODO: can be duplicated ids + jobs[id] = { + id, + fileList, + isDeclFile: true, + isInCycle, + isAbcJob: false, + dependencies: Array.from(dependencies), // 依赖external program + dependants: [] + }; + } + + private addJobToQueues(job: Job, queues: Queues) { + if (queues.externalProgramQueue.some(j => j.id === job.id) || + queues.abcQueue.some(j => j.id === job.id)) { + return; + } + + if (!job.isAbcJob) { + console.log("addJobToQueues: adding program job: ", job) + queues.externalProgramQueue.push(job); + } else { + console.log("addJobToQueues: adding abc job: ", job) + queues.abcQueue.push(job); + } + } + + private initCompileQueues(jobs: Record, queues: Queues): void { + this.collectCompileJobs(jobs); + Object.values(jobs).forEach(job => { + if (job.dependencies.length === 0) { + this.addJobToQueues(job, queues); + } + }); + } + + private checkAllTasksDone(queues: Queues, workerPool: WorkerInfo[]): boolean { + if (queues.externalProgramQueue.length === 0) { + for (let i = 0; i < workerPool.length; i++) { + if (!workerPool[i].isIdle) { + return false; + } + } + return true; + } + return false; + } + + // private checkAllTasksDone(jobs: Record, queues: Queues, processingJobs: Set, + // workers: ThreadWorker[], config: number, globalContext: number): void { + // const allJobs = Object.values(jobs); + // const allDone = allJobs.every(job => + // !queues.externalProgramQueue.some(j => j.id === job.id) && + // !queues.abcQueue.some(j => j.id === job.id) && + // !processingJobs.has(job.id) + // ); + + // if (allDone) { + // console.log("All tasks completed. Exiting..."); + // workers.forEach(worker => worker.postMessage({ type: 'EXIT' })); + // // setTimeout(() => process.exit(0), 100); + // this.processAfterCompile(config, globalContext); + // } + // } + + private processAfterCompile(config: number, globalContext: number): void { + + if (this.hasCleanWorker) { + return; + } + this.hasCleanWorker = true; + let arktsGlobal = this.buildConfig.arktsGlobal; + let arkts = this.buildConfig.arkts; + + arktsGlobal.es2panda._DestroyGlobalContext(globalContext); + arkts.destroyConfig(config); + arktsGlobal.es2panda._MemFinalize(); + + this.mergeAbcFiles(); + } + + private invokeWorkers(jobs: Record, queues: Queues, processingJobs: Set, workers: ThreadWorker[]) { + const that = this; + return new Promise((resolve) => { + const numWorkers = 1; + + let files: string[] = []; + + Object.entries(jobs).forEach(([key, job]) => { + for (let i = 0; i < job.fileList.length; i++) { + files.push(job.fileList[i]); + } + }); + + let arkts = this.buildConfig.arkts; + let fileInfo = this.compileFiles.values().next().value!; + + let ets2pandaCmd: string[] = [ + '_', + '--extension', + 'ets', + '--arktsconfig', + fileInfo.arktsConfigFile, + '--output', + fileInfo.abcFilePath, + ]; + + if (that.isDebug) { + ets2pandaCmd.push('--debug-info'); + } + ets2pandaCmd.push(fileInfo.filePath); + + arkts.MemInitialize(); + + let config = arkts.Config.create(ets2pandaCmd).peer; + + let globalContextPtr = arkts.CreateGlobalContext(config, files, files.length); + const serializableConfig = that.getSerializableConfig(); + + const workerPool: WorkerInfo[] = []; + for (let i = 0; i < numWorkers; i++) { + const worker = new ThreadWorker( + path.resolve(__dirname, 'compile_thread_worker.js'), + { workerData: { workerId: i } } + ); + + workers.push(worker); + workerPool.push({ worker, isIdle: true }); + that.assignTaskToIdleWorker(workerPool[i], queues, processingJobs, serializableConfig, globalContextPtr); + + worker.on('message', (msg) => { + if (msg.type === 'TASK_FINISH') { + const workerInfo = workerPool.find(w => w.worker === worker); + if (workerInfo) { + workerInfo.isIdle = true; + } + console.log('[JIAKAI DEBUG] [MASTER] finished job: ', msg.jobId); + const jobId = msg.jobId; + finishedJob.push(jobId); + processingJobs.delete(jobId); + const completedJob = jobs[jobId]; + completedJob.dependants.forEach(depJobId => { + const depJob = jobs[depJobId]; + console.log('[JIAKAI DEBUG] [MASTER] depJobId: ', depJobId); + const depIndex = depJob.dependencies.indexOf(jobId); + if (depIndex !== -1) { + depJob.dependencies.splice(depIndex, 1); + if (depJob.dependencies.length === 0) { + console.log('[JIAKAI DEBUG] [MASTER] addJobToQueues start: ', depJobId); + that.addJobToQueues(depJob, queues); + } + } + }); + for (let j = 0; j < workerPool.length; j++) { + if (workerPool[j].isIdle) { + // console.log('=====for======assignTaskToIdleWorker===') + // console.log('workerPool[i].isIdle: ', j, ' ', workerPool[j].isIdle) + that.assignTaskToIdleWorker(workerPool[j], queues, processingJobs, serializableConfig, globalContextPtr); + } + } + } + if (that.checkAllTasksDone(queues, workerPool)) { + console.log("All tasks completed. Exiting..."); + + console.log('[JIAKAI DEBUG] ALL FINISHED JOBS: ', JSON.stringify(finishedJob, null, 2)); + console.log('[JIAKAI DEBUG] ALL NON-FINISHED JOBS: ', JSON.stringify(Object.keys(jobs).filter(j => !finishedJob.includes(j)), null, 2)) + + workers.forEach(worker => worker.postMessage({ type: 'EXIT' })); + that.processAfterCompile(config, globalContextPtr); + resolve() + } + }); + } + }); + } + + private assignTaskToIdleWorker(workerInfo: WorkerInfo, queues: Queues, processingJobs: Set, serializableConfig: Object, globalContextPtr: number) { + let job: Job | undefined; + let jobInfo: JobInfo | undefined; + + if (queues.externalProgramQueue.length > 0) { + job = queues.externalProgramQueue.shift()!; + console.log('queues.externalProgramQueue.length: ', queues.externalProgramQueue.length); + jobInfo = { + id: job.id, + isCompileAbc: false + }; + } + else if (queues.abcQueue.length > 0) { + job = queues.abcQueue.shift()!; + console.log('queues.abcQueue.length: ', queues.abcQueue.length); + jobInfo = { + id: job.id, + isCompileAbc: true + }; + } + + if (job) { + console.log('======== [MASTER] ASSIGN_TASK=========', job.id) + console.log('======== [MASTER] ASSIGN_TASK========= job: ', job) + processingJobs.add(job.id); + jobInfo!.compileFileInfo = this.compileFiles.get(job.fileList[0]); + jobInfo!.buildConfig = serializableConfig; + jobInfo!.globalContextPtr = globalContextPtr; + workerInfo.worker.postMessage({ type: 'ASSIGN_TASK', jobInfo }); + workerInfo.isIdle = false; + } + } + + public async runConcunrent(): Promise { + this.generateModuleInfos(); + this.generateArkTSConfigForModules(); + + const jobs: Record = {}; + const queues: Queues = { + externalProgramQueue: [], + abcQueue: [], + }; + this.initCompileQueues(jobs, queues); + + const processingJobs = new Set(); + const workers: ThreadWorker[] = []; + await this.invokeWorkers(jobs, queues, processingJobs, workers); + } +} + +interface WorkerInfo { + worker: ThreadWorker; + isIdle: boolean; } + +interface Job { + id: string; + isDeclFile: boolean; + isInCycle?: boolean; + fileList: string[]; + dependencies: string[]; + dependants: string[]; + isAbcJob: boolean; +} + +interface Queues { + externalProgramQueue: Job[]; + abcQueue: Job[]; +} + +interface JobInfo { + id: string; + isCompileAbc: boolean; // change to enum + compileFileInfo?: CompileFileInfo; + buildConfig?: Object; + globalContextPtr?: number; +} + +interface FileDepsInfo { + dependencies: Record; + dependants: Record; +} + + +function createHash(str: string): string { + const hash = crypto.createHash('sha256'); + hash.update(str); + return hash.digest('hex'); +} + + // -- runConcurrent code ends -- + +let finishedJob: string[] = []; \ No newline at end of file diff --git a/ets2panda/driver/build_system/src/build/build_mode.ts b/ets2panda/driver/build_system/src/build/build_mode.ts index 4c797a308a7e1f6f67bcee059b1dbfe484d2c7dc..dec6da2594eb5f97f5f025bdb7023c99b8f41358 100644 --- a/ets2panda/driver/build_system/src/build/build_mode.ts +++ b/ets2panda/driver/build_system/src/build/build_mode.ts @@ -26,6 +26,10 @@ export class BuildMode extends BaseMode { } public async run(): Promise { - await super.runParallell(); + console.time("test"); + // await super.runParallell(); + + await super.runConcunrent(); + console.timeEnd("test") } } \ No newline at end of file diff --git a/ets2panda/driver/build_system/src/build/compile_thread_worker.ts b/ets2panda/driver/build_system/src/build/compile_thread_worker.ts new file mode 100644 index 0000000000000000000000000000000000000000..0245cddf618860a81257674ec5e1a4f02dfa67d2 --- /dev/null +++ b/ets2panda/driver/build_system/src/build/compile_thread_worker.ts @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { parentPort, workerData } from 'worker_threads'; +import { CompileFileInfo } from '../types'; +import * as fs from 'fs'; +import * as path from 'path'; +import { ensurePathExists } from '../utils'; +import { KOALA_WRAPPER_PATH_FROM_SDK } from '../pre_define'; +import { PluginDriver, PluginHook } from '../plugins/plugins_driver'; +import { + BuildConfig, +} from '../types'; +import { + BUILD_MODE +} from '../pre_define'; +import { + LogData, + LogDataFactory, + Logger +} from '../logger'; +import { ErrorCode } from '../error_code'; + +const { workerId } = workerData; + +function compileAbc(jobInfo: any) { + console.log(jobInfo); + Logger.getInstance(jobInfo.buildConfig); + PluginDriver.getInstance().initPlugins(jobInfo.buildConfig); + const koalaWrapperPath = path.resolve(jobInfo.buildConfig.buildSdkPath, KOALA_WRAPPER_PATH_FROM_SDK); + let { arkts, arktsGlobal } = require(koalaWrapperPath); + const isDebug = jobInfo.buildConfig.buildMode === BUILD_MODE.DEBUG; + + let errorStatus = false; + try { + let fileInfo = jobInfo.compileFileInfo; + ensurePathExists(fileInfo.abcFilePath); + + const ets2pandaCmd = [ + '_', '--extension', 'ets', + '--arktsconfig', fileInfo.arktsConfigFile, + '--output', fileInfo.abcFilePath, + ]; + + if (isDebug) { + ets2pandaCmd.push('--debug-info'); + } + ets2pandaCmd.push(fileInfo.filePath); + + let config = arkts.Config.create(ets2pandaCmd).peer; + + let context = arkts.Context.createCacheContextFromFile(config, fileInfo.filePath, jobInfo.globalContextPtr, false).peer; + + PluginDriver.getInstance().getPluginContext().setContextPtr(context); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, context); + + PluginDriver.getInstance().runPluginHook(PluginHook.PARSED); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, context); + + PluginDriver.getInstance().runPluginHook(PluginHook.CHECKED); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_BIN_GENERATED, context); + } catch (error) { + errorStatus = true; + if (error instanceof Error) { + const logData: LogData = LogDataFactory.newInstance( + ErrorCode.BUILDSYSTEM_COMPILE_ABC_FAIL, + 'Compile abc files failed.', + error.message + ); + Logger.getInstance().printError(logData); + } + } finally { + if (!errorStatus) { + // when error occur,wrapper will destroy context. + // arktsGlobal.es2panda._DestroyContext(arktsGlobal.compilerContext.peer); + } + // PluginDriver.getInstance().runPluginHook(PluginHook.CLEAN); + // arkts.destroyConfig(arktsGlobal.config); + } +} + +function compileExternalProgram(jobInfo: any) { + console.log(jobInfo); + Logger.getInstance(jobInfo.buildConfig); + PluginDriver.getInstance().initPlugins(jobInfo.buildConfig); + const koalaWrapperPath = path.resolve(jobInfo.buildConfig.buildSdkPath, KOALA_WRAPPER_PATH_FROM_SDK); + let { arkts, arktsGlobal } = require(koalaWrapperPath); + const isDebug = jobInfo.buildConfig.buildMode === BUILD_MODE.DEBUG; + + let errorStatus = false; + try { + let fileInfo = jobInfo.compileFileInfo; + const ets2pandaCmd = ['-', '--extension', 'ets', '--arktsconfig', fileInfo.arktsConfigFile]; + + if (isDebug) { + ets2pandaCmd.push('--debug-info'); + } + ets2pandaCmd.push(fileInfo.filePath); + + console.log(ets2pandaCmd.join(' ')); + fs.appendFileSync("./test.log", ets2pandaCmd.join(' ') + "\n"); + + let config = arkts.Config.create(ets2pandaCmd).peer; + + let context = arkts.Context.createCacheContextFromFile(config, fileInfo.filePath, jobInfo.globalContextPtr, true).peer; + + PluginDriver.getInstance().getPluginContext().setContextPtr(context); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_PARSED, context); + + PluginDriver.getInstance().runPluginHook(PluginHook.PARSED); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_CHECKED, context); + + PluginDriver.getInstance().runPluginHook(PluginHook.CHECKED); + + arkts.proceedToState(arkts.Es2pandaContextState.ES2PANDA_STATE_LOWERED, context); + } catch (error) { + console.log(error) + errorStatus = true; + if (error instanceof Error) { + const logData: LogData = LogDataFactory.newInstance( + ErrorCode.BUILDSYSTEM_COMPILE_ABC_FAIL, + 'Compile external program files failed.', + error.message + ); + Logger.getInstance().printError(logData); + } + } finally { + if (!errorStatus) { + // when error occur,wrapper will destroy context. + // arktsGlobal.es2panda._DestroyContext(arktsGlobal.compilerContext.peer); + } + // PluginDriver.getInstance().runPluginHook(PluginHook.CLEAN); + // arkts.destroyConfig(arktsGlobal.config); + } +} + +parentPort?.on('message', (msg) => { + if (msg.type === 'ASSIGN_TASK') { + const job = msg.jobInfo; + console.log(`======= [WORKER] Worker ${workerId} processing Job ${job.id}`); + fs.appendFileSync('./test.log', 'ASSIGN_TASK:: id:: ' + JSON.stringify(job.id) + '\n'); + fs.appendFileSync('./test.log', 'ASSIGN_TASK:: compileFileInfo:: ' + JSON.stringify(job.compileFileInfo) + '\n'); + + if (job.isCompileAbc) { + compileAbc(job); + } else { + let a = Date.now(); + compileExternalProgram(job); + let b = Date.now(); + console.log('compileExternalProgram time', b - a, 'ms'); + } + + console.log(`[JIAKAI DEBUG] [WORKER] Worker ${workerId} finished Job ${job.id}`); + parentPort?.postMessage({ + type: 'TASK_FINISH', + jobId: job.id, + workerId, + }); + } else if (msg.type === 'EXIT') { + console.log(`[JIAKAI DEBUG] [WORKER] Worker ${workerId} exiting...`); + process.exit(0); + } +}); diff --git a/ets2panda/driver/build_system/src/entry.ts b/ets2panda/driver/build_system/src/entry.ts index 5d70b509d0278ddb18ba907684efff63aacdb2a4..b07f3bfc6bb5210ab6dc1ac5d7d1166e3465c119 100644 --- a/ets2panda/driver/build_system/src/entry.ts +++ b/ets2panda/driver/build_system/src/entry.ts @@ -27,7 +27,7 @@ import { BuildConfig } from './types'; export async function build(projectConfig: BuildConfig): Promise { Logger.getInstance(projectConfig); let buildConfig: BuildConfig = processBuildConfig(projectConfig); - + buildConfig.entryFiles = buildConfig.compileFiles; if (projectConfig.enableDeclgenEts2Ts === true) { let buildMode: BuildMode = new BuildMode(buildConfig); buildMode.generateDeclaration(); diff --git a/ets2panda/driver/build_system/src/init/process_build_config.ts b/ets2panda/driver/build_system/src/init/process_build_config.ts index 7a9d599ee1eb67da6eeebbe187a2a7504ad092a5..ac1128f86b7e79a1ae2ca9c7f301a22a474cdc6a 100644 --- a/ets2panda/driver/build_system/src/init/process_build_config.ts +++ b/ets2panda/driver/build_system/src/init/process_build_config.ts @@ -57,10 +57,13 @@ function initPlatformSpecificConfig(buildConfig: BuildConfig): void { const logger: Logger = Logger.getInstance(); if (isWindows()) { buildConfig.abcLinkerPath = path.join(pandaSdkPath, 'bin', 'ark_link.exe'); + buildConfig.depAnalyzerPath = path.join(pandaSdkPath, 'bin', 'dependency_analyzer.exe'); + } if (isMac() || isLinux()) { buildConfig.abcLinkerPath = path.join(pandaSdkPath, 'bin', 'ark_link'); + buildConfig.depAnalyzerPath = path.join(pandaSdkPath, 'bin', 'dependency_analyzer'); } if (!fs.existsSync(buildConfig.abcLinkerPath as string)) { @@ -90,6 +93,7 @@ export function initBuildEnv(buildConfig: BuildConfig): void { function initKoalaWrapper(buildConfig: BuildConfig): void { let koalaWrapperPath: string = path.resolve(buildConfig.buildSdkPath as string, KOALA_WRAPPER_PATH_FROM_SDK); + console.log("koalaWrapperPath: ", koalaWrapperPath); const { arkts, arktsGlobal } = require(koalaWrapperPath); buildConfig.arkts = arkts; buildConfig.arktsGlobal = arktsGlobal; diff --git a/ets2panda/driver/build_system/src/plugins/plugins_driver.ts b/ets2panda/driver/build_system/src/plugins/plugins_driver.ts index 4184b13b9f05eda9ffdf4abcac9e1e563998c57f..86915320f54407a9b5f9bcf021abefd6b4891505 100644 --- a/ets2panda/driver/build_system/src/plugins/plugins_driver.ts +++ b/ets2panda/driver/build_system/src/plugins/plugins_driver.ts @@ -69,11 +69,13 @@ class PluginContext { private ast: object | undefined; private program: object | undefined; private projectConfig: object | undefined; + private contextPtr: number | undefined; constructor() { this.ast = undefined; this.program = undefined; this.projectConfig = undefined; + this.contextPtr = undefined; } public setArkTSAst(ast: object): void { @@ -93,21 +95,20 @@ class PluginContext { } public setProjectConfig(projectConfig: object): void { - if (this.projectConfig) { - const logData: LogData = LogDataFactory.newInstance( - ErrorCode.BUILDSYSTEM_PLUGIN_CONTEXT_RESET_PROJECT_CONFIG, - 'Trying to reset projectConfig in PluginContext, abort compiling.', - 'projectConfig in PluginContext can only be set once.' - ); - Logger.getInstance().printErrorAndExit(logData); - return; - } this.projectConfig = projectConfig; } public getProjectConfig(): object | undefined { return this.projectConfig; } + + public setContextPtr(ptr: number): void { + this.contextPtr = ptr; +} + +public getContextPtr(): number | undefined { + return this.contextPtr; +} } export class PluginDriver { diff --git a/ets2panda/driver/build_system/src/types.ts b/ets2panda/driver/build_system/src/types.ts index 76cff513de5b50f5e59d9e4cad53ac5cee4956a2..1ade0e5d0ec05a5c179c29a7f0ad9b838b76d03a 100644 --- a/ets2panda/driver/build_system/src/types.ts +++ b/ets2panda/driver/build_system/src/types.ts @@ -36,6 +36,10 @@ export interface ArkTSGlobal { }; es2panda: { _DestroyContext: Function; + _MemInitialize: Function; + _MemFinalize: Function; + _CreateGlobalContext: Function; + _DestroyGlobalContext: Function; } } @@ -53,6 +57,8 @@ export interface ArkTS { generateTsDeclarationsFromContext: Function; destroyConfig: Function; Es2pandaContextState: typeof Es2pandaContextState; + MemInitialize: Function; + CreateGlobalContext: Function; } export enum Es2pandaContextState { @@ -81,6 +87,7 @@ export interface PathConfig { pandaStdlibPath?: string; // path to panda sdk stdlib, for local test externalApiPaths: string[]; abcLinkerPath?: string; + depAnalyzerPath?: string; } export interface DeclgenConfig { @@ -110,6 +117,7 @@ export interface DependentModuleConfig { export interface BuildConfig extends BuildBaseConfig, DeclgenConfig, LoggerConfig, ModuleConfig, PathConfig { plugins: PluginsConfig; compileFiles: string[]; + entryFiles?: string[]; dependentModuleList: DependentModuleConfig[]; } // ProjectConfig ends diff --git a/ets2panda/driver/build_system/test/demo_hap/build_config.json b/ets2panda/driver/build_system/test/demo_hap/build_config.json index 59193da7a0c69939c08da835cda3ca67aba92c5f..fe5935097beab68e55f267f6399514d95615df97 100644 --- a/ets2panda/driver/build_system/test/demo_hap/build_config.json +++ b/ets2panda/driver/build_system/test/demo_hap/build_config.json @@ -1,18 +1,19 @@ { "compileFiles": [ - "${absolute_path_to_build_system}/test/demo_hap/entry/b.ets", - "${absolute_path_to_build_system}/test/demo_hap/entry/c.ets", - "${absolute_path_to_build_system}/test/demo_hap/entry/d.ets", - "${absolute_path_to_build_system}/test/demo_hap/harA/index.ets", - "${absolute_path_to_build_system}/test/demo_hap/harB/indexB.ets" + "/mnt/data/huyunhui/openharmony-ArkTS1.2/arkcompiler/ets_frontend/ets2panda/driver/build_system/test/demo_hap/entry/b.ets", + "/mnt/data/huyunhui/openharmony-ArkTS1.2/arkcompiler/ets_frontend/ets2panda/driver/build_system/test/demo_hap/entry/c.ets", + "/mnt/data/huyunhui/openharmony-ArkTS1.2/arkcompiler/ets_frontend/ets2panda/driver/build_system/test/demo_hap/entry/d.ets", + "/mnt/data/huyunhui/openharmony-ArkTS1.2/arkcompiler/ets_frontend/ets2panda/driver/build_system/test/demo_hap/harA/index.ets", + "/mnt/data/huyunhui/openharmony-ArkTS1.2/arkcompiler/ets_frontend/ets2panda/driver/build_system/test/demo_hap/harB/indexB.ets" ], "packageName": "entry", "moduleType": "shared", + "hasMainModule": true, "buildType": "build", "buildMode": "Debug", - "moduleRootPath": "${absolute_path_to_build_system}/test/demo_hap/entry/", + "moduleRootPath": "/mnt/data/huyunhui/openharmony-ArkTS1.2/arkcompiler/ets_frontend/ets2panda/driver/build_system/test/demo_hap/entry/", "sourceRoots": ["./", "src/main1/ets"], "loaderOutPath": "./dist", @@ -22,14 +23,14 @@ "declgenV1OutPath": "./dist/declgen/decl_ets", "declgenBridgeCodePath": "./dist/declgen/ets", - "buildSdkPath": "${absolute_path_to_build_system}/test/mock_sdk/", + "buildSdkPath": "/mnt/data/huyunhui/openharmony-ArkTS1.2/out/sdk/ohos-sdk/linux/ets/ets1.2", "dependentModuleList": [ { "packageName": "harA", "moduleName": "harA", "moduleType": "har", - "modulePath": "${absolute_path_to_build_system}/test/demo_hap/harA", + "modulePath": "/mnt/data/huyunhui/openharmony-ArkTS1.2/arkcompiler/ets_frontend/ets2panda/driver/build_system/test/demo_hap/harA", "sourceRoots": ["./"], "entryFile": "index.ets", "language": "1.2" @@ -38,7 +39,7 @@ "packageName": "harB", "moduleName": "harB", "moduleType": "har", - "modulePath": "${absolute_path_to_build_system}/test/demo_hap/harB", + "modulePath": "/mnt/data/huyunhui/openharmony-ArkTS1.2/arkcompiler/ets_frontend/ets2panda/driver/build_system/test/demo_hap/harB", "sourceRoots": ["./"], "entryFile": "indexB.ets", "language": "1.2" diff --git a/ets2panda/driver/build_system/test/demo_hap/entry/a.ets b/ets2panda/driver/build_system/test/demo_hap/entry/a.ets index 76a66d7bbfd24d99a07b0ee71e0e6225ec62d355..03e10fb47a6de6ecbe014b8d1d67cb7008d8f24a 100644 --- a/ets2panda/driver/build_system/test/demo_hap/entry/a.ets +++ b/ets2panda/driver/build_system/test/demo_hap/entry/a.ets @@ -13,7 +13,22 @@ * limitations under the License. */ + +import {str, strd} from './c' +import {strA} from 'harA' +import {strB} from 'harB' + function main() { let a: string = "hello world" console.log(a) + + console.log(strd); + + console.log(strA); + console.log(strB); + + console.log("end hello world a.ets") } + +let stra = "hello world from a" +export {stra} \ No newline at end of file diff --git a/ets2panda/driver/build_system/test/demo_hap/entry/b.ets b/ets2panda/driver/build_system/test/demo_hap/entry/b.ets index cc677f2f571d961d6978d102705cdc2778b00054..2a81b659a423d0a9a271b86560bdb4f7c15c2c80 100644 --- a/ets2panda/driver/build_system/test/demo_hap/entry/b.ets +++ b/ets2panda/driver/build_system/test/demo_hap/entry/b.ets @@ -16,18 +16,27 @@ import {str, strd} from './c' import {strA} from 'harA' import {strB} from 'harB' -import {UIAbility, Lang, Hilog} from '@kit.AbilityKit' +// import {UIAbility, Lang, Hilog} from '@kit.AbilityKit' + +// import {stra} from "./a" function main() { - let ui = new UIAbility(); - let lan = new Lang(); - let hilog = new Hilog(); +// let ui = new UIAbility(); +// let lan = new Lang(); +// let hilog = new Hilog(); let hello_str = str; console.log(hello_str); console.log(strd); + // console.log(stra); console.log(strA); console.log(strB); + + console.log("end hello world b.ets") +} + +export function foo() { + console.log("foo in b"); } \ No newline at end of file diff --git a/ets2panda/driver/build_system/test/demo_hap/entry/c.ets b/ets2panda/driver/build_system/test/demo_hap/entry/c.ets index bfbc0dd50e88078824c60ed21c1c68e9b22a98cc..1fd443aa1fdb951bdf3c705862fc6c663fceeac7 100644 --- a/ets2panda/driver/build_system/test/demo_hap/entry/c.ets +++ b/ets2panda/driver/build_system/test/demo_hap/entry/c.ets @@ -13,7 +13,9 @@ * limitations under the License. */ -import {strd} from './d' +import {strd, strArr} from './d' + +let d: string[] = strArr; export let str: string = "hello world from c!"; export {strd} \ No newline at end of file diff --git a/ets2panda/driver/build_system/test/demo_hap/entry/d.ets b/ets2panda/driver/build_system/test/demo_hap/entry/d.ets index 0cd8a4308447c0ddce876a8f243663267d63afcc..a880df3c2adb64491a1c5891f5494217bd4dbbe2 100644 --- a/ets2panda/driver/build_system/test/demo_hap/entry/d.ets +++ b/ets2panda/driver/build_system/test/demo_hap/entry/d.ets @@ -13,4 +13,9 @@ * limitations under the License. */ -export let strd: string = "hello world from d!"; \ No newline at end of file +// import {foo} from './b'; + +// foo(); + +export let strd: string = "hello world from d!"; +export let strArr: string[] = ['1', '2']; \ No newline at end of file diff --git a/ets2panda/driver/dependency_analyzer/BUILD.gn b/ets2panda/driver/dependency_analyzer/BUILD.gn index 8fc5e7492f7138630cd7137f16bb34345f61422a..7adcfb1a6f565278fc786f55e57e84c7e7f4b833 100644 --- a/ets2panda/driver/dependency_analyzer/BUILD.gn +++ b/ets2panda/driver/dependency_analyzer/BUILD.gn @@ -20,21 +20,37 @@ ohos_executable("dependency_analyzer") { "main.cpp", ] - include_dirs = [ "$target_gen_dir" ] - configs = [ "$ark_root:ark_config", + "$ark_root/assembler:arkassembler_public_config", "$ark_es2panda_root:libes2panda_public_config", + "$ark_root/libpandafile:arkfile_public_config", + "$ark_root/libpandabase:arkbase_public_config", + "$ark_root/bytecode_optimizer:bytecodeopt_public_config", + "$ark_root/compiler:arkcompiler_public_config", + "$ark_root/runtime:arkruntime_public_config", ] deps = [ "$ark_es2panda_root:libes2panda_frontend_static", "$ark_es2panda_root:libes2panda_public_frontend_static", ] + + if (ark_standalone_build) { + deps += [ + "$ark_root/bytecode_optimizer:libarktsbytecodeopt_package", + "$ark_root/libpandabase:libarktsbase_package", + "$ark_root/libpandafile:libarktsfile_package", + ] + } + external_deps = [ + "runtime_core:libarktsassembler_package", + "runtime_core:libarktsbase_package", "runtime_core:libarktsbytecodeopt_package", "runtime_core:libarktscompiler_package", "runtime_core:libarktsfile_package", + sdk_libc_secshared_dep, ] libs = platform_libs diff --git a/ets2panda/driver/dependency_analyzer/dep_analyzer.cpp b/ets2panda/driver/dependency_analyzer/dep_analyzer.cpp index 143beae568e43bcf0d4b7cd84ec57a97808f011d..23321fa1e2a5e666b72d0979bd15c3897a482326 100644 --- a/ets2panda/driver/dependency_analyzer/dep_analyzer.cpp +++ b/ets2panda/driver/dependency_analyzer/dep_analyzer.cpp @@ -14,6 +14,19 @@ */ #include "dep_analyzer.h" +#include + +std::string escapeBackslashes(const std::string& path) { + std::string result; + for (char c : path) { + if (c == '\\') { + result += "\\\\"; + } else { + result += c; + } + } + return result; +} void DepAnalyzer::Dump(std::string &outFilePath) { @@ -23,18 +36,60 @@ void DepAnalyzer::Dump(std::string &outFilePath) return; } - for (auto const &sp : sourcePaths_) { - outFile << sp << std::endl; - } + Dump(outFile); outFile.close(); } void DepAnalyzer::Dump(std::ostream &ostr) { - for (auto const &sp : sourcePaths_) { - ostr << sp << std::endl; + std::string jsonTab = " "; + ostr << "{\n"; + + ostr << jsonTab << "\"dependencies\": {\n"; + bool isFirst = true; + for (auto [file, deps] : fileDirectDependencies_) { + if (!isFirst) { + ostr << ",\n"; + } else { + isFirst = false; + } + ostr << jsonTab << jsonTab << "\"" << escapeBackslashes(file) << "\": ["; + bool isFirst2 = true; + for (auto const &dep : deps) { + if (!isFirst2) { + ostr << ", "; + } else { + isFirst2 = false; + } + ostr << "\"" << escapeBackslashes(dep) << "\""; + } + ostr << "]"; } + ostr << "\n" << jsonTab << "},\n"; + + ostr << jsonTab << "\"dependants\": {\n"; + isFirst = true; + for (auto [file, deps] : fileDirectDependants_) { + if (!isFirst) { + ostr << ",\n"; + } else { + isFirst = false; + } + ostr << jsonTab << jsonTab << "\"" << escapeBackslashes(file) << "\": ["; + bool isFirst2 = true; + for (auto const &dep : deps) { + if (!isFirst2) { + ostr << ", "; + } else { + isFirst2 = false; + } + ostr << "\"" << escapeBackslashes(dep) << "\""; + } + ostr << "]"; + } + ostr << "\n" << jsonTab << "}\n"; + ostr << "}"; } void DepAnalyzer::AddImports(ark::es2panda::parser::ETSParser *parser) @@ -50,37 +105,131 @@ void DepAnalyzer::AddImports(ark::es2panda::parser::ETSParser *parser) } } -int DepAnalyzer::AnalyzeDeps(int argc, const char **argv) +std::map> DepAnalyzer::AnalyzeDepsForMultiFiles( + const char *exec, std::vector &fileList, std::string &arktsconfig) { - int minArgCount = 2; - if (argc < minArgCount) { - std::cout << "No file has been entered for analysis" << std::endl; - return 1; + std::set parsedFileList; + std::queue parseFileList; + for (auto &file : fileList) { + parseFileList.push(file); } - const auto *impl = es2panda_GetImpl(ES2PANDA_LIB_VERSION); - auto *cfg = impl->CreateConfig(argc, argv); - if (cfg == nullptr) { - return 1; + impl->MemInitialize(); + + while (!parseFileList.empty()) { + auto file = parseFileList.front(); + parseFileList.pop(); + + es2panda_Config *cfg = nullptr; + if (!arktsconfig.empty()) { + // NOLINTNEXTLINE + const char *args[] = {exec, file.c_str(), arktsconfig.c_str()}; + cfg = impl->CreateConfig(sizeof(args) / sizeof(char *), args); + } else { + // NOLINTNEXTLINE + const char *args[] = {exec, file.c_str()}; + cfg = impl->CreateConfig(sizeof(args) / sizeof(char *), args); + } + + if (cfg == nullptr) { + std::cerr << "Failed to create config" << std::endl; + std::abort(); + } + auto *cfgImpl = reinterpret_cast(cfg); + auto parserInputCStr = cfgImpl->options->CStrParserInputContents().first; + + es2panda_Context *ctx = + impl->CreateContextFromString(cfg, parserInputCStr, cfgImpl->options->SourceFileName().c_str()); + auto *ctxImpl = reinterpret_cast(ctx); + impl->ProceedToState(ctx, ES2PANDA_STATE_PARSED); + + if (ctxImpl->state == ES2PANDA_STATE_ERROR) { + std::cout << "Parse Failed: "<< ctxImpl->errorMessage << std::endl; + delete cfgImpl->options; + delete cfgImpl->diagnosticEngine; + delete cfgImpl; + std::abort(); + } + + ark::es2panda::parser::Program *mainProgram = ctxImpl->parserProgram; + std::string mainProgramAbsPath = std::string {mainProgram->AbsoluteName()}; + // std::cout << "mainProgramAbsPath: " << mainProgramAbsPath << std::endl; + + parsedFileList.insert(mainProgramAbsPath); + MergeFileDeps(mainProgram); + + // for (auto &[_, progs] : mainProgram->DirectExternalSources()) { + // for (auto prog : progs) { + // auto progAbsPath = std::string {prog->AbsoluteName()}; + // fileDirectDependencies_[mainProgramAbsPath].insert(progAbsPath); + // fileDirectDependants_[progAbsPath].insert(mainProgramAbsPath); + + // if (ParsedFileList.count(progAbsPath) == 0) { + // std::cout << "push file: " << progAbsPath << std::endl; + // ParseFileList.push(progAbsPath); + // // parseFileSet.insert(progAbsPath); + // } + // } + // } + + impl->DestroyContext(ctx); + impl->DestroyConfig(cfg); + } + impl->MemFinalize(); + return fileDirectDependencies_; +} + +void DepAnalyzer::MergeFileDeps(ark::es2panda::parser::Program *mainProgram) { + for (const auto& [key, valueSet] : mainProgram->GetFileDependencies()) { + fileDirectDependencies_[key].insert(valueSet.begin(), valueSet.end()); } - auto *cfgImpl = reinterpret_cast(cfg); - auto parserInputCStr = cfgImpl->options->CStrParserInputContents().first; - es2panda_Context *ctx = - impl->CreateContextFromString(cfg, parserInputCStr, cfgImpl->options->SourceFileName().c_str()); - auto *ctxImpl = reinterpret_cast(ctx); - ctxImpl->parser->SetParserStatus(ark::es2panda::parser::ParserStatus::DEPENDENCY_ANALYZER_MODE); - impl->ProceedToState(ctx, ES2PANDA_STATE_PARSED); + for (const auto& [key, valueSet] : mainProgram->GetFileDependants()) { + fileDirectDependants_[key].insert(valueSet.begin(), valueSet.end()); + } +} - if (ctxImpl->state == ES2PANDA_STATE_ERROR) { - std::cout << ctxImpl->errorMessage << std::endl; +static void AddFileList(std::string &fileListPath, std::vector &fileList) +{ + std::ifstream inFile(fileListPath); + if (!inFile.is_open()) { + std::cerr << "Error when opening a file " << fileListPath << std::endl; + return; + } + std::string line; + while (getline(inFile, line)) { + if (!line.empty()) { + fileList.emplace_back(line); + } + } +} + +int DepAnalyzer::AnalyzeDeps(int argc, const char **argv) +{ + // NOLINTBEGIN + int minArgCount = 2; + if (argc < minArgCount) { + std::cout << "No file has been entered for analysis" << std::endl; return 1; } - auto *parser = reinterpret_cast(ctxImpl->parser); - AddImports(parser); + std::string arktsconfig; + std::vector fileList; + for (int i = 1; i < argc; i++) { + if (std::strncmp(argv[i], "--arktsconfig=", std::strlen("--arktsconfig=")) == 0) { + arktsconfig = argv[i]; + continue; + } - impl->DestroyContext(ctx); - impl->DestroyConfig(cfg); + if (std::strncmp(argv[i], "@", std::strlen("@")) == 0) { + std::string arg = argv[i]; + std::string fileListPath = arg.substr(std::strlen("@")); + AddFileList(fileListPath, fileList); + continue; + } + fileList.emplace_back(argv[i]); + } + AnalyzeDepsForMultiFiles(argv[0], fileList, arktsconfig); return 0; + // NOLINTEND } \ No newline at end of file diff --git a/ets2panda/driver/dependency_analyzer/dep_analyzer.h b/ets2panda/driver/dependency_analyzer/dep_analyzer.h index 777fe1b9380c6ba3a8d6dd60797cdd6312cdc6ff..87f051e2f09d33badf47d9410c97fdd0b0f844fb 100644 --- a/ets2panda/driver/dependency_analyzer/dep_analyzer.h +++ b/ets2panda/driver/dependency_analyzer/dep_analyzer.h @@ -26,6 +26,9 @@ class DepAnalyzer { public: int AnalyzeDeps(int argc, const char **argv); + std::map> AnalyzeDepsForMultiFiles(const char *exec, + std::vector &fileList, + std::string &arktsconfig); void Dump(std::string &outFilePath); void Dump(std::ostream &ostr = std::cout); @@ -36,8 +39,11 @@ public: private: void AddImports(ark::es2panda::parser::ETSParser *parser); + void MergeFileDeps(ark::es2panda::parser::Program *mainProgram); std::vector sourcePaths_; + std::map> fileDirectDependencies_; + std::map> fileDirectDependants_; }; #endif // ES2PANDA_DEPENDENCY_ANALYZER_H diff --git a/ets2panda/es2panda.cpp b/ets2panda/es2panda.cpp index c6fc6881cf723e94d270226e77adb2ed1a77f48a..f63eadd63c095633536ca96514613fc97ecf6bca 100644 --- a/ets2panda/es2panda.cpp +++ b/ets2panda/es2panda.cpp @@ -96,5 +96,5 @@ void Compiler::DumpAsm(const pandasm::Program *prog) compiler::CompilerImpl::DumpAsm(prog); } -util::DiagnosticEngine *g_diagnosticEngine = nullptr; +thread_local util::DiagnosticEngine *g_diagnosticEngine = nullptr; } // namespace ark::es2panda diff --git a/ets2panda/es2panda.h b/ets2panda/es2panda.h index d21a4cf8440ac806f815c7dab6525c4b8693489e..c96de2133fea8f3effeb769eec3074e061ff8b3b 100644 --- a/ets2panda/es2panda.h +++ b/ets2panda/es2panda.h @@ -129,7 +129,7 @@ private: // g_diagnosticEngine used only for flush diagnostic before unexpected process termination: // - inside SIGSEGV handler -extern util::DiagnosticEngine *g_diagnosticEngine; +thread_local extern util::DiagnosticEngine *g_diagnosticEngine; } // namespace ark::es2panda #endif diff --git a/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp b/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp index e78fd348d346ec89dd67765cb6de41ce4c2a8cba..e1101e2b0037ff38a6ab9cb79ec45a030dfd40cd 100644 --- a/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp +++ b/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp @@ -68,7 +68,7 @@ ir::ClassDeclaration *ClassBuilder::Build(parser::Program *program) && classDecl->SetParent(programAst); // Here we assume that global statements of the passed `program` are not currently checked, so that // insertion is safe. - programAst->Statements().push_back(classDecl); + programAst->AddStatement(classDecl); return classDecl; } diff --git a/ets2panda/evaluate/scopedDebugInfoPlugin.cpp b/ets2panda/evaluate/scopedDebugInfoPlugin.cpp index fc8666dc9ebbb6231b6b31fa2bf9673f0ddfe407..a82c57ba3d46f33b05d08b343471ab3f8892812b 100644 --- a/ets2panda/evaluate/scopedDebugInfoPlugin.cpp +++ b/ets2panda/evaluate/scopedDebugInfoPlugin.cpp @@ -149,7 +149,7 @@ bool ScopedDebugInfoPlugin::InsertReturnStatement() // which will also modify method signature's return type. auto *evalMethodStatements = context_.methodStatements; - auto &statementsList = evalMethodStatements->Statements(); + auto &statementsList = evalMethodStatements->StatmentsForUpdates(); // Omit the emplaced `DebuggerAPI.setLocal<>` calls and find the original last statement. auto lastStatementIter = std::find(statementsList.rbegin(), statementsList.rend(), lastStatement); ES2PANDA_ASSERT(lastStatementIter != statementsList.rend()); @@ -195,7 +195,7 @@ void ScopedDebugInfoPlugin::AddPrologueEpilogue(ir::BlockStatement *block) } // Prepend prologue. - auto &statements = block->Statements(); + auto &statements = block->StatmentsForUpdates(); for (auto *stmt : iter->second.first) { statements.insert(statements.begin(), stmt); } diff --git a/ets2panda/ir/annotationAllowed.h b/ets2panda/ir/annotationAllowed.h index 0053c073dc9ce0a2cc91e6e6b80bbe7304135ad2..0309ad48d0ad8a1770f98d60dd39fa9679ab86e7 100644 --- a/ets2panda/ir/annotationAllowed.h +++ b/ets2panda/ir/annotationAllowed.h @@ -19,6 +19,7 @@ #include "ir/astNode.h" #include "ir/statement.h" #include "ir/statements/annotationUsage.h" +#include "util/es2pandaMacros.h" namespace ark::es2panda::ir { @@ -31,24 +32,65 @@ public: NO_COPY_OPERATOR(AnnotationAllowed); NO_MOVE_SEMANTIC(AnnotationAllowed); - [[nodiscard]] ArenaVector &Annotations() noexcept + void EmplaceAnnotations(AnnotationUsage *source) { - return annotations_; + auto newNode = reinterpret_cast *>(this->GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + newNode->annotations_.emplace_back(source); + } + + void ClearAnnotations() + { + auto newNode = reinterpret_cast *>(this->GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + newNode->annotations_.clear(); + } + + void SetValueAnnotations(AnnotationUsage *source, size_t index) + { + auto newNode = reinterpret_cast *>(this->GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + auto &arenaVector = newNode->annotations_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = source; + }; + + void TransformAnnotations(const NodeTransformer &cb, std::string_view const transformationName) + { + auto &annotations = Annotations(); + for (size_t ix = 0; ix < annotations.size(); ix++) { + if (auto *transformedNode = cb(annotations[ix]); annotations[ix] != transformedNode) { + annotations[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueAnnotations(transformedNode->AsAnnotationUsage(), ix); + } + } + } + + const ArenaVector &Annotations() + { + return AstNode::GetOrCreateHistoryNodeAs>()->annotations_; } [[nodiscard]] const ArenaVector &Annotations() const noexcept { - return annotations_; + return AstNode::GetHistoryNodeAs>()->annotations_; } - void SetAnnotations(ArenaVector &&annotations) + void SetAnnotations(const ArenaVector &&annotationList) { - annotations_ = std::move(annotations); - for (ir::AnnotationUsage *anno : annotations_) { - anno->SetParent(this); + auto &annotations = AstNode::GetOrCreateHistoryNodeAs>()->annotations_; + annotations = ArenaVector {std::move(annotationList)}; + + for (auto annotation : Annotations()) { + annotation->SetParent(this); } } + void AddAnnotations(AnnotationUsage *annotations) + { + AstNode::GetOrCreateHistoryNodeAs>()->annotations_.emplace_back(annotations); + } + protected: explicit AnnotationAllowed(Expression const &other, ArenaAllocator *allocator) : T(other), annotations_(allocator->Adapter()) @@ -82,11 +124,6 @@ protected: { } - void AddAnnotations(AnnotationUsage *const annotations) - { - annotations_.emplace_back(annotations); - } - AnnotationAllowed(AnnotationAllowed const &other) : T(static_cast(other)), annotations_(other.annotations_.get_allocator()) { diff --git a/ets2panda/ir/as/namedType.cpp b/ets2panda/ir/as/namedType.cpp index 7bf5f66ecbc38e3e9c0da0d9778078a0bad6ac03..48880e158992324656f677fc6c14b7cf8f6a4a10 100644 --- a/ets2panda/ir/as/namedType.cpp +++ b/ets2panda/ir/as/namedType.cpp @@ -45,12 +45,7 @@ void NamedType::TransformChildren(const NodeTransformer &cb, std::string_view co } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void NamedType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/astNode.cpp b/ets2panda/ir/astNode.cpp index 3acbcae47c98a6f4d3f63394b43eb50ebd50d362..8be6f1ec5d37bb94dd18f18648d72712e6649e48 100644 --- a/ets2panda/ir/astNode.cpp +++ b/ets2panda/ir/astNode.cpp @@ -15,57 +15,60 @@ #include "astNode.h" #include "ir/astDump.h" +#include "ir/astNodeHistory.h" #include "ir/srcDump.h" #include "ir/typed.h" +#include "compiler/lowering/phase.h" namespace ark::es2panda::ir { AstNode::AstNode(AstNode const &other) { - range_ = other.range_; - type_ = other.type_; - if (other.variable_ != nullptr) { - variable_ = other.variable_; + auto otherHistoryNode = other.GetHistoryNode(); + range_ = otherHistoryNode->range_; + type_ = otherHistoryNode->type_; + if (otherHistoryNode->variable_ != nullptr) { + variable_ = otherHistoryNode->variable_; } - flags_ = other.flags_; - astNodeFlags_ = other.astNodeFlags_; + flags_ = otherHistoryNode->flags_; + astNodeFlags_ = otherHistoryNode->astNodeFlags_; // boxing_unboxing_flags_ {}; leave default value! } [[nodiscard]] bool AstNode::IsExported() const noexcept { if (UNLIKELY(IsClassDefinition())) { - return parent_->IsExported(); + return GetHistoryNode()->parent_->IsExported(); } - return (flags_ & ModifierFlags::EXPORT) != 0; + return (Modifiers() & ModifierFlags::EXPORT) != 0; } [[nodiscard]] bool AstNode::IsDefaultExported() const noexcept { if (UNLIKELY(IsClassDefinition())) { - return parent_->IsDefaultExported(); + return GetHistoryNode()->parent_->IsDefaultExported(); } - return (flags_ & ModifierFlags::DEFAULT_EXPORT) != 0; + return (Modifiers() & ModifierFlags::DEFAULT_EXPORT) != 0; } [[nodiscard]] bool AstNode::IsExportedType() const noexcept { if (UNLIKELY(IsClassDefinition())) { - return this->parent_->IsExportedType(); + return GetHistoryNode()->parent_->IsExportedType(); } - return (flags_ & ModifierFlags::EXPORT_TYPE) != 0; + return (Modifiers() & ModifierFlags::EXPORT_TYPE) != 0; } [[nodiscard]] bool AstNode::HasExportAlias() const noexcept { if (UNLIKELY(IsClassDefinition())) { - return parent_->HasExportAlias(); + return GetHistoryNode()->parent_->HasExportAlias(); } - return (astNodeFlags_ & AstNodeFlags::HAS_EXPORT_ALIAS) != 0; + return (GetHistoryNode()->astNodeFlags_ & AstNodeFlags::HAS_EXPORT_ALIAS) != 0; } bool AstNode::IsScopeBearer() const noexcept @@ -240,18 +243,30 @@ std::string AstNode::DumpDecl() const void AstNode::SetOriginalNode(AstNode *originalNode) noexcept { - originalNode_ = originalNode; + if (OriginalNode() != originalNode) { + GetOrCreateHistoryNode()->originalNode_ = originalNode; + } } AstNode *AstNode::OriginalNode() const noexcept { - return originalNode_; + return GetHistoryNode()->originalNode_; +} + +const std::optional> &AstNode::TransformedNode() const noexcept +{ + return GetHistoryNode()->transformedNode_; } void AstNode::SetTransformedNode(std::string_view const transformationName, AstNode *transformedNode) { + // ES2PANDA_ASSERT(!TransformedNode().has_value()); transformedNode->SetOriginalNode(this); - transformedNode_ = std::make_optional(std::make_pair(transformationName, transformedNode)); + + if (transformedNode != nullptr) { + GetOrCreateHistoryNode()->transformedNode_ = + std::make_optional(std::make_pair(transformationName, transformedNode)); + } } void AstNode::CleanUp() @@ -267,33 +282,33 @@ void AstNode::CleanUp() bool AstNode::IsReadonly() const noexcept { - return (flags_ & ModifierFlags::READONLY) != 0; + return (Modifiers() & ModifierFlags::READONLY) != 0; } // NOTE: For readonly parameter type bool AstNode::IsReadonlyType() const noexcept { - return (flags_ & ModifierFlags::READONLY_PARAMETER) != 0; + return (Modifiers() & ModifierFlags::READONLY_PARAMETER) != 0; } bool AstNode::IsOptionalDeclaration() const noexcept { - return (flags_ & ModifierFlags::OPTIONAL) != 0; + return (Modifiers() & ModifierFlags::OPTIONAL) != 0; } bool AstNode::IsDefinite() const noexcept { - return (flags_ & ModifierFlags::DEFINITE) != 0; + return (Modifiers() & ModifierFlags::DEFINITE) != 0; } bool AstNode::IsConstructor() const noexcept { - return (flags_ & ModifierFlags::CONSTRUCTOR) != 0; + return (Modifiers() & ModifierFlags::CONSTRUCTOR) != 0; } bool AstNode::IsOverride() const noexcept { - return (flags_ & ModifierFlags::OVERRIDE) != 0; + return (Modifiers() & ModifierFlags::OVERRIDE) != 0; } AstNode *AstNode::ShallowClone(ArenaAllocator *allocator) @@ -312,6 +327,7 @@ void AstNode::CopyTo(AstNode *other) const other->flags_ = flags_; other->astNodeFlags_ = astNodeFlags_; other->boxingUnboxingFlags_ = boxingUnboxingFlags_; + other->history_ = history_; other->variable_ = variable_; other->originalNode_ = originalNode_; other->transformedNode_ = transformedNode_; @@ -321,4 +337,100 @@ AstNode *AstNode::Construct([[maybe_unused]] ArenaAllocator *allocator) { ES2PANDA_UNREACHABLE(); } + +bool AstNode::IsValidInCurrentPhase() const +{ + if (!HistoryEnabled()) { + return true; + } + return compiler::GetPhaseManager()->CurrentPhaseId() >= GetFirstCreated(); +} + +compiler::PhaseId AstNode::GetFirstCreated() const +{ + return history_->FirstCreated(); +} + +AstNode *AstNode::GetHistoryNode() const +{ + AstNode *node = nullptr; + + if (HistoryEnabled()) { + node = history_->Get(compiler::GetPhaseManager()->CurrentPhaseId()); + } else { + node = const_cast(this); + } + + ES2PANDA_ASSERT(node != nullptr); + return node; +} + +bool AstNode::CheckProgramLowered(const AstNode* node) +{ + const parser::Program* result = nullptr; + while (node) { + if (node->Range().start.Program()) { + result = node->Range().start.Program(); + } + node = node->Parent(); + } + ES2PANDA_ASSERT(result != nullptr); + return result->IsASTLowered(); +} + +AstNode *AstNode::GetOrCreateHistoryNode() const +{ + AstNode *node = nullptr; + + if (HistoryEnabled()) { + node = history_->At(compiler::GetPhaseManager()->CurrentPhaseId()); + if (node == nullptr) { + // ASSERT_GO_THROUGH(!CheckProgramLowered(this)); + node = history_->Get(compiler::GetPhaseManager()->PreviousPhaseId()); + ES2PANDA_ASSERT(node != nullptr); + node = node->ShallowClone(compiler::GetPhaseManager()->Allocator()); + history_->Set(node, compiler::GetPhaseManager()->CurrentPhaseId()); + } + } else { + node = const_cast(this); + } + + return node; +} + +void AstNode::AddModifier(ModifierFlags const flags) noexcept +{ + if (!All(Modifiers(), flags)) { + GetOrCreateHistoryNode()->flags_ |= flags; + } +} + +void AstNode::ClearModifier(ModifierFlags const flags) noexcept +{ + if (Any(Modifiers(), flags)) { + GetOrCreateHistoryNode()->flags_ &= ~flags; + } +} + +void AstNode::EnableHistory() +{ + if (g_mainFileDisableHistory || HistoryEnabled()) { + return; + } + + history_ = compiler::GetPhaseManager()->Allocator()->New( + this, compiler::GetPhaseManager()->CurrentPhaseId(), compiler::GetPhaseManager()->Allocator()); +} + +bool AstNode::HistoryEnabled() const +{ + return history_ != nullptr; +} + +bool InCheckerPhase() +{ + return compiler::GetPhaseManager()->InCheckerPhase(); +} + + } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/astNode.h b/ets2panda/ir/astNode.h index 355b707e69bf81d55a30aa7310df48fb261f696a..d6161bfa9a01d6d932f3eada184242d3a5096342 100644 --- a/ets2panda/ir/astNode.h +++ b/ets2panda/ir/astNode.h @@ -19,6 +19,7 @@ #include "es2panda.h" #include "astNodeFlags.h" #include "astNodeMapping.h" +#include "compiler/lowering/phase_id.h" #include "ir/visitor/AstVisitor.h" #include "lexer/token/sourceLocation.h" #include "util/es2pandaMacros.h" @@ -41,6 +42,9 @@ class Scope; } // namespace ark::es2panda::varbinder namespace ark::es2panda::ir { + +inline thread_local bool g_mainFileDisableHistory; + // NOLINTBEGIN(modernize-avoid-c-arrays) inline constexpr char const CLONE_ALLOCATION_ERROR[] = "Unsuccessful allocation during cloning."; // NOLINTEND(modernize-avoid-c-arrays) @@ -96,6 +100,7 @@ inline std::string_view ToString(AstNodeType nodeType) #undef STRING_FROM_NODE_TYPE // Forward declarations +class AstNodeHistory; class AstDumper; class Expression; class SrcDumper; @@ -127,31 +132,31 @@ public: bool IsProgram() const { - return parent_ == nullptr; + return GetHistoryNode()->parent_ == nullptr; } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DECLARE_IS_CHECKS(nodeType, className) \ - bool Is##className() const \ - { \ - /* CC-OFFNXT(G.PRE.02) name part*/ \ - /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ - return type_ == AstNodeType::nodeType; /* CC-OFF(G.PRE.02) name part*/ \ +#define DECLARE_IS_CHECKS(nodeType, className) \ + bool Is##className() const \ + { \ + /* CC-OFFNXT(G.PRE.02) name part*/ \ + /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ + return GetHistoryNode()->type_ == AstNodeType::nodeType; /* CC-OFF(G.PRE.02) name part*/ \ } AST_NODE_MAPPING(DECLARE_IS_CHECKS) #undef DECLARE_IS_CHECKS // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DECLARE_IS_CHECKS(nodeType1, nodeType2, baseClass, reinterpretClass) \ - bool Is##baseClass() const \ - { \ - /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ - return type_ == AstNodeType::nodeType1; /* CC-OFF(G.PRE.02) name part*/ \ - } \ - bool Is##reinterpretClass() const \ - { \ - /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ - return type_ == AstNodeType::nodeType2; /* CC-OFF(G.PRE.02) name part*/ \ +#define DECLARE_IS_CHECKS(nodeType1, nodeType2, baseClass, reinterpretClass) \ + bool Is##baseClass() const \ + { \ + /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ + return GetHistoryNode()->type_ == AstNodeType::nodeType1; /* CC-OFF(G.PRE.02) name part*/ \ + } \ + bool Is##reinterpretClass() const \ + { \ + /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ + return GetHistoryNode()->type_ == AstNodeType::nodeType2; /* CC-OFF(G.PRE.02) name part*/ \ } AST_NODE_REINTERPRET_MAPPING(DECLARE_IS_CHECKS) #undef DECLARE_IS_CHECKS @@ -265,62 +270,72 @@ public: void SetRange(const lexer::SourceRange &loc) noexcept { - range_ = loc; + if (GetHistoryNode()->range_ != loc) { + GetOrCreateHistoryNode()->range_ = loc; + } } void SetStart(const lexer::SourcePosition &start) noexcept { - range_.start = start; + if (GetHistoryNode()->range_.start != start) { + GetOrCreateHistoryNode()->range_.start = start; + } } void SetEnd(const lexer::SourcePosition &end) noexcept { - range_.end = end; + if (GetHistoryNode()->range_.end != end) { + GetOrCreateHistoryNode()->range_.end = end; + } } [[nodiscard]] const lexer::SourcePosition &Start() const noexcept { - return range_.start; + return GetHistoryNode()->range_.start; } [[nodiscard]] const lexer::SourcePosition &End() const noexcept { - return range_.end; + return GetHistoryNode()->range_.end; } [[nodiscard]] const lexer::SourceRange &Range() const noexcept { - return range_; + return GetHistoryNode()->range_; } [[nodiscard]] AstNodeType Type() const noexcept { - return type_; + return GetHistoryNode()->type_; } [[nodiscard]] AstNode *Parent() noexcept { - return parent_; + return GetHistoryNode()->parent_; } [[nodiscard]] const AstNode *Parent() const noexcept { - return parent_; + return GetHistoryNode()->parent_; } void SetParent(AstNode *const parent) noexcept { - parent_ = parent; + if (GetHistoryNode()->parent_ != parent) { + GetOrCreateHistoryNode()->parent_ = parent; + } } [[nodiscard]] varbinder::Variable *Variable() const noexcept { - return variable_; + return GetHistoryNode()->variable_; } void SetVariable(varbinder::Variable *variable) noexcept { - variable_ = variable; + if (GetHistoryNode()->variable_ != variable) { + GetOrCreateHistoryNode()->variable_ = variable; + } } // When no decorators are allowed, we cannot return a reference to an empty vector. @@ -354,62 +369,62 @@ public: void SetOverride() noexcept { - flags_ |= ModifierFlags::OVERRIDE; + AddModifier(ModifierFlags::OVERRIDE); } [[nodiscard]] bool IsAsync() const noexcept { - return (flags_ & ModifierFlags::ASYNC) != 0; + return (Modifiers() & ModifierFlags::ASYNC) != 0; } [[nodiscard]] bool IsSynchronized() const noexcept { - return (flags_ & ModifierFlags::SYNCHRONIZED) != 0; + return (Modifiers() & ModifierFlags::SYNCHRONIZED) != 0; } [[nodiscard]] bool IsNative() const noexcept { - return (flags_ & ModifierFlags::NATIVE) != 0; + return (Modifiers() & ModifierFlags::NATIVE) != 0; } [[nodiscard]] bool IsConst() const noexcept { - return (flags_ & ModifierFlags::CONST) != 0; + return (Modifiers() & ModifierFlags::CONST) != 0; } [[nodiscard]] bool IsStatic() const noexcept { - return (flags_ & ModifierFlags::STATIC) != 0; + return (Modifiers() & ModifierFlags::STATIC) != 0; } [[nodiscard]] bool IsFinal() const noexcept { - return (flags_ & ModifierFlags::FINAL) != 0U; + return (Modifiers() & ModifierFlags::FINAL) != 0U; } [[nodiscard]] bool IsAbstract() const noexcept { - return (flags_ & ModifierFlags::ABSTRACT) != 0; + return (Modifiers() & ModifierFlags::ABSTRACT) != 0; } [[nodiscard]] bool IsPublic() const noexcept { - return (flags_ & ModifierFlags::PUBLIC) != 0; + return (Modifiers() & ModifierFlags::PUBLIC) != 0; } [[nodiscard]] bool IsProtected() const noexcept { - return (flags_ & ModifierFlags::PROTECTED) != 0; + return (Modifiers() & ModifierFlags::PROTECTED) != 0; } [[nodiscard]] bool IsPrivate() const noexcept { - return (flags_ & ModifierFlags::PRIVATE) != 0; + return (Modifiers() & ModifierFlags::PRIVATE) != 0; } [[nodiscard]] bool IsInternal() const noexcept { - return (flags_ & ModifierFlags::INTERNAL) != 0; + return (Modifiers() & ModifierFlags::INTERNAL) != 0; } [[nodiscard]] bool IsExported() const noexcept; @@ -420,42 +435,36 @@ public: [[nodiscard]] bool IsDeclare() const noexcept { - return (flags_ & ModifierFlags::DECLARE) != 0; + return (Modifiers() & ModifierFlags::DECLARE) != 0; } [[nodiscard]] bool IsIn() const noexcept { - return (flags_ & ModifierFlags::IN) != 0; + return (Modifiers() & ModifierFlags::IN) != 0; } [[nodiscard]] bool IsOut() const noexcept { - return (flags_ & ModifierFlags::OUT) != 0; + return (Modifiers() & ModifierFlags::OUT) != 0; } [[nodiscard]] bool IsSetter() const noexcept { - return (flags_ & ModifierFlags::SETTER) != 0; + return (Modifiers() & ModifierFlags::SETTER) != 0; } - void AddModifier(ModifierFlags const flags) noexcept - { - flags_ |= flags; - } + void AddModifier(ModifierFlags const flags) noexcept; - void ClearModifier(ModifierFlags const flags) noexcept - { - flags_ &= ~flags; - } + void ClearModifier(ModifierFlags const flags) noexcept; [[nodiscard]] ModifierFlags Modifiers() noexcept { - return flags_; + return GetHistoryNode()->flags_; } [[nodiscard]] ModifierFlags Modifiers() const noexcept { - return flags_; + return GetHistoryNode()->flags_; } [[nodiscard]] bool HasExportAlias() const noexcept; @@ -464,28 +473,34 @@ public: #define DECLARE_FLAG_OPERATIONS(flag_type, member_name) \ void Set##flag_type(flag_type flags) const noexcept \ { \ - (member_name) = flags; \ + if (GetHistoryNode()->member_name != flags) { \ + GetOrCreateHistoryNode()->member_name = flags; \ + } \ } \ \ void Add##flag_type(flag_type flag) const noexcept \ { \ - (member_name) |= flag; \ + if (!All(GetHistoryNode()->member_name, flag)) { \ + GetOrCreateHistoryNode()->member_name |= flag; \ + } \ } \ \ [[nodiscard]] flag_type Get##flag_type() const noexcept \ { \ /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ - return (member_name); \ + return GetHistoryNode()->member_name; \ } \ \ bool Has##flag_type(flag_type flag) const noexcept \ { \ /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ - return ((member_name)&flag) != 0U; \ + return (GetHistoryNode()->member_name & flag) != 0U; \ } \ void Remove##flag_type(flag_type flag) const noexcept \ { \ - (member_name) &= ~flag; \ + if (Any(GetHistoryNode()->member_name, flag)) { \ + GetOrCreateHistoryNode()->member_name &= ~flag; \ + } \ } DECLARE_FLAG_OPERATIONS(BoxingUnboxingFlags, boxingUnboxingFlags_); @@ -551,6 +566,21 @@ public: AstNode *ShallowClone(ArenaAllocator *allocator); + static bool CheckProgramLowered(const AstNode* node); + + AstNode *GetOrCreateHistoryNodeParent() + { + auto parent = Parent(); + if (parent == nullptr) { + return nullptr; + } + return parent->GetOrCreateHistoryNode(); + } + bool IsValidInCurrentPhase() const; + + AstNode *GetHistoryNode() const; + AstNode *GetOrCreateHistoryNode() const; + protected: AstNode(AstNode const &other); @@ -560,7 +590,24 @@ protected: void SetType(AstNodeType const type) noexcept { - type_ = type; + if (Type() != type) { + GetOrCreateHistoryNode()->type_ = type; + } + } + + void EnableHistory(); + bool HistoryEnabled() const; + + template + T *GetHistoryNodeAs() const + { + return reinterpret_cast(GetHistoryNode()); + } + + template + T *GetOrCreateHistoryNodeAs() const + { + return reinterpret_cast(GetOrCreateHistoryNode()); } friend class SizeOfNodeTest; @@ -571,11 +618,15 @@ protected: ModifierFlags flags_ {}; mutable AstNodeFlags astNodeFlags_ {}; mutable BoxingUnboxingFlags boxingUnboxingFlags_ {}; + AstNodeHistory *history_ {nullptr}; // NOLINTEND(misc-non-private-member-variables-in-classes) private: + compiler::PhaseId GetFirstCreated() const; AstNode &operator=(const AstNode &) = default; + const std::optional> &TransformedNode() const noexcept; + varbinder::Variable *variable_ {}; AstNode *originalNode_ = nullptr; // {lowering_phase_name, new_generated_node} @@ -593,12 +644,14 @@ public: [[nodiscard]] TypeNode *TypeAnnotation() const noexcept { - return typeAnnotation_; + return AstNode::GetHistoryNodeAs>()->typeAnnotation_; } void SetTsTypeAnnotation(TypeNode *const typeAnnotation) noexcept { - typeAnnotation_ = typeAnnotation; + if (TypeAnnotation() != typeAnnotation) { + AstNode::GetOrCreateHistoryNodeAs>()->typeAnnotation_ = typeAnnotation; + } } void CopyTo(AstNode *other) const override @@ -661,5 +714,7 @@ private: Span data_; }; +bool InCheckerPhase(); + } // namespace ark::es2panda::ir #endif diff --git a/ets2panda/ir/astNodeFlags.h b/ets2panda/ir/astNodeFlags.h index 20af517c70946944fb455a78d3b83c41732978e4..ba60c42c0a41f4fac1f9e1a4374df108f5fa339b 100644 --- a/ets2panda/ir/astNodeFlags.h +++ b/ets2panda/ir/astNodeFlags.h @@ -104,6 +104,7 @@ enum class ScriptFunctionFlags : uint32_t { ASYNC_IMPL = 1U << 19U, EXTERNAL_OVERLOAD = 1U << 20U, HAS_THROW = 1U << 21U, + IN_RECORD = 1U << 22U, }; enum class TSOperatorType { READONLY, KEYOF, UNIQUE }; diff --git a/ets2panda/ir/astNodeHistory.cpp b/ets2panda/ir/astNodeHistory.cpp index c27d68e8d203ad21cf24960d112e264f3eddd580..89a87fad299473798267c7760a06e1e8a1a62c73 100644 --- a/ets2panda/ir/astNodeHistory.cpp +++ b/ets2panda/ir/astNodeHistory.cpp @@ -18,12 +18,12 @@ namespace ark::es2panda::ir { -AstNodeHistory::AstNodeHistory(AstNode *node, int32_t phaseId, ArenaAllocator *allocator) : list_ {allocator} +AstNodeHistory::AstNodeHistory(AstNode *node, compiler::PhaseId phaseId, ArenaAllocator *allocator) : list_ {allocator} { Set(node, phaseId); } -AstNode *AstNodeHistory::FindBackwardEquals(int32_t phaseId) +AstNode *AstNodeHistory::FindBackwardEquals(compiler::PhaseId phaseId) { auto item = item_; @@ -37,7 +37,7 @@ AstNode *AstNodeHistory::FindBackwardEquals(int32_t phaseId) return nullptr; } -AstNode *AstNodeHistory::FindForwardEquals(int32_t phaseId) +AstNode *AstNodeHistory::FindForwardEquals(compiler::PhaseId phaseId) { auto item = item_; @@ -53,7 +53,7 @@ AstNode *AstNodeHistory::FindForwardEquals(int32_t phaseId) // Find node state precisely at phase with a given ID // (e.g. find the node history record with `phaseId` equal to a given value) -AstNode *AstNodeHistory::At(int32_t phaseId) +AstNode *AstNodeHistory::At(compiler::PhaseId phaseId) { if (LIKELY(item_->data.phaseId == phaseId)) { // Start searching with last accessed item @@ -70,7 +70,7 @@ AstNode *AstNodeHistory::At(int32_t phaseId) // Find node state at phase with a given ID // (e.g. find last node history record with `phaseId` less or equal to a given value) -AstNode *AstNodeHistory::Get(int32_t phaseId) +AstNode *AstNodeHistory::Get(compiler::PhaseId phaseId) { auto found = FindLessOrEquals(phaseId); if (LIKELY(found != nullptr)) { @@ -82,7 +82,7 @@ AstNode *AstNodeHistory::Get(int32_t phaseId) } // Find node state at phase with a given ID and set its new value, insert new history record if not found -void AstNodeHistory::Set(AstNode *node, int32_t phaseId) +void AstNodeHistory::Set(AstNode *node, compiler::PhaseId phaseId) { HistoryRecord record {node, phaseId}; if (LIKELY(list_.Empty() || list_.Tail()->data.phaseId < phaseId)) { @@ -105,7 +105,7 @@ void AstNodeHistory::Set(AstNode *node, int32_t phaseId) // Find node state at phase with a given ID // (e.g. find last node history record with `phaseId` less or equal to a given value) -AstNodeHistory::HistoryList::Item *AstNodeHistory::FindLessOrEquals(int32_t phaseId) +AstNodeHistory::HistoryList::Item *AstNodeHistory::FindLessOrEquals(compiler::PhaseId phaseId) { // Start searching with last accessed item auto item = item_; @@ -136,6 +136,10 @@ AstNodeHistory::HistoryList::Item *AstNodeHistory::FindLessOrEquals(int32_t phas if (item->data.phaseId <= phaseId) { return item; } + if (item->data.phaseId > phaseId && item->prev != nullptr) { + item = item->prev; + return item; + } } return nullptr; diff --git a/ets2panda/ir/astNodeHistory.h b/ets2panda/ir/astNodeHistory.h index 8aebde4a7a90a7dfc83bce7065edb2d3394256dd..ffad5b770d44cb381af449ba0873964b69659169 100644 --- a/ets2panda/ir/astNodeHistory.h +++ b/ets2panda/ir/astNodeHistory.h @@ -17,29 +17,34 @@ #define ES2PANDA_IR_AST_NODE_HISTORY_H #include "ir/astNode.h" +#include "compiler/lowering/phase_id.h" #include "util/doubleLinkedList.h" namespace ark::es2panda::ir { class AstNodeHistory { public: - AstNodeHistory(AstNode *node, int32_t phaseId, ArenaAllocator *allocator); + AstNodeHistory(AstNode *node, compiler::PhaseId phaseId, ArenaAllocator *allocator); - AstNode *At(int32_t phaseId); - AstNode *Get(int32_t phaseId); - void Set(AstNode *node, int32_t phaseId); + AstNode *At(compiler::PhaseId phaseId); + AstNode *Get(compiler::PhaseId phaseId); + void Set(AstNode *node, compiler::PhaseId phaseId); + compiler::PhaseId FirstCreated() + { + return list_.Head()->data.phaseId; + } private: struct HistoryRecord { AstNode *node; - int32_t phaseId; + compiler::PhaseId phaseId; }; using HistoryList = util::ArenaDoubleLinkedList; - AstNode *FindBackwardEquals(int32_t phaseId); - AstNode *FindForwardEquals(int32_t phaseId); - HistoryList::Item *FindLessOrEquals(int32_t phaseId); + AstNode *FindBackwardEquals(compiler::PhaseId phaseId); + AstNode *FindForwardEquals(compiler::PhaseId phaseId); + HistoryList::Item *FindLessOrEquals(compiler::PhaseId phaseId); HistoryList list_; // Node history list HistoryList::Item *item_ {nullptr}; // Last accessed history record diff --git a/ets2panda/ir/base/classDefinition.cpp b/ets2panda/ir/base/classDefinition.cpp index 3bf590dd44ee17129ac765356b7d6939d21193e6..45005ceb88a1af17c9b420aa25f4c1accfd87b7a 100644 --- a/ets2panda/ir/base/classDefinition.cpp +++ b/ets2panda/ir/base/classDefinition.cpp @@ -28,28 +28,47 @@ #include "ir/ts/tsClassImplements.h" namespace ark::es2panda::ir { + +SETTER_FOR_CHILD(ClassDefinition, Ctor, ctor_, MethodDefinition *); +SETTER_FOR_CHILD(ClassDefinition, TypeParams, typeParams_, TSTypeParameterDeclaration *); +SETTER_FOR_CHILD(ClassDefinition, OrigEnumDecl, origEnumDecl_, TSEnumDeclaration *); +SETTER_FOR_CHILD(ClassDefinition, AnonClass, anonClass_, ClassDeclaration *); +SETTER_FOR_CHILD(ClassDefinition, SuperClass, superClass_, Expression *); +SETTER_FOR_CHILD(ClassDefinition, SuperTypeParams, superTypeParams_, TSTypeParameterInstantiation *); + +SETTER_FOR_FIELD(ClassDefinition, Scope, scope_, varbinder::LocalScope *); +SETTER_FOR_FIELD(ClassDefinition, Modifiers, modifiers_, ClassDefinitionModifiers); +SETTER_FOR_FIELD(ClassDefinition, InternalName, internalName_, util::StringView); + +SETTER_FOR_ARENAVECTOR_CHILD(ClassDefinition, Body, body_, AstNode *); +SETTER_FOR_ARENAVECTOR_CHILD(ClassDefinition, Implements, implements_, TSClassImplements *); + const FunctionExpression *ClassDefinition::Ctor() const { - return ctor_ != nullptr ? ctor_->Value()->AsFunctionExpression() : nullptr; + auto const newNode = GetHistoryNode()->AsClassDefinition(); + return newNode->ctor_ != nullptr ? newNode->ctor_->Value()->AsFunctionExpression() : nullptr; } bool ClassDefinition::HasPrivateMethod() const { - return std::any_of(body_.cbegin(), body_.cend(), [](auto *element) { + auto const body = Body(); + return std::any_of(body.cbegin(), body.cend(), [](auto const *element) { return element->IsMethodDefinition() && element->AsClassElement()->IsPrivateElement(); }); } bool ClassDefinition::HasNativeMethod() const { - return std::any_of(body_.cbegin(), body_.cend(), [](auto *element) { + auto const body = Body(); + return std::any_of(body.cbegin(), body.cend(), [](auto const *element) { return element->IsMethodDefinition() && element->AsMethodDefinition()->IsNative(); }); } bool ClassDefinition::HasComputedInstanceField() const { - return std::any_of(body_.cbegin(), body_.cend(), [](auto *element) { + auto const body = Body(); + return std::any_of(body.cbegin(), body.cend(), [](auto *element) { return element->IsClassProperty() && element->AsClassElement()->IsComputed() && !(element->AsClassElement()->Modifiers() & ir::ModifierFlags::STATIC); }); @@ -57,115 +76,125 @@ bool ClassDefinition::HasComputedInstanceField() const bool ClassDefinition::HasMatchingPrivateKey(const util::StringView &name) const { - return std::any_of(body_.cbegin(), body_.cend(), [&name](auto *element) { + auto const body = Body(); + return std::any_of(body.cbegin(), body.cend(), [&name](auto *element) { return element->AsClassElement()->IsPrivateElement() && element->AsClassElement()->Id()->Name() == name; }); } void ClassDefinition::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - if (ident_ != nullptr) { - if (auto *transformedNode = cb(ident_); ident_ != transformedNode) { - ident_->SetTransformedNode(transformationName, transformedNode); - ident_ = transformedNode->AsIdentifier(); + auto const ident = Ident(); + if (ident != nullptr) { + if (auto *transformedNode = cb(ident); ident != transformedNode) { + ident->SetTransformedNode(transformationName, transformedNode); + SetIdent(transformedNode->AsIdentifier()); } } - if (typeParams_ != nullptr) { - if (auto *transformedNode = cb(typeParams_); typeParams_ != transformedNode) { - typeParams_->SetTransformedNode(transformationName, transformedNode); - typeParams_ = transformedNode->AsTSTypeParameterDeclaration(); + auto const typeParam = TypeParams(); + if (typeParam != nullptr) { + if (auto *transformedNode = cb(typeParam); typeParam != transformedNode) { + typeParam->SetTransformedNode(transformationName, transformedNode); + SetTypeParams(transformedNode->AsTSTypeParameterDeclaration()); } } - if (superClass_ != nullptr) { - if (auto *transformedNode = cb(superClass_); superClass_ != transformedNode) { - superClass_->SetTransformedNode(transformationName, transformedNode); - superClass_ = transformedNode->AsExpression(); + auto const superClass = SuperClass(); + if (superClass != nullptr) { + if (auto *transformedNode = cb(superClass); superClass != transformedNode) { + superClass->SetTransformedNode(transformationName, transformedNode); + SetSuperClass(transformedNode->AsExpression()); } } - if (superTypeParams_ != nullptr) { - if (auto *transformedNode = cb(superTypeParams_); superTypeParams_ != transformedNode) { - superTypeParams_->SetTransformedNode(transformationName, transformedNode); - superTypeParams_ = transformedNode->AsTSTypeParameterInstantiation(); + auto const superTypeParam = SuperTypeParams(); + if (superTypeParam != nullptr) { + if (auto *transformedNode = cb(superTypeParam); superTypeParam != transformedNode) { + superTypeParam->SetTransformedNode(transformationName, transformedNode); + SetSuperTypeParams(transformedNode->AsTSTypeParameterInstantiation()); } } - for (auto *&it : VectorIterationGuard(implements_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsTSClassImplements(); + auto const &implement = Implements(); + for (size_t ix = 0; ix < implement.size(); ix++) { + if (auto *transformedNode = cb(implement[ix]); implement[ix] != transformedNode) { + implement[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueImplements(transformedNode->AsTSClassImplements(), ix); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); - if (ctor_ != nullptr) { - if (auto *transformedNode = cb(ctor_); ctor_ != transformedNode) { - ctor_->SetTransformedNode(transformationName, transformedNode); - ctor_ = transformedNode->AsMethodDefinition(); + auto const &ctor = Ctor(); + if (ctor != nullptr) { + if (auto *transformedNode = cb(ctor); ctor != transformedNode) { + ctor->SetTransformedNode(transformationName, transformedNode); + SetCtor(transformedNode->AsMethodDefinition()); } } // Survives adding new elements to the end // NOLINTNEXTLINE(modernize-loop-convert) - for (size_t ix = 0; ix < body_.size(); ix++) { - if (auto *transformedNode = cb(body_[ix]); body_[ix] != transformedNode) { - body_[ix]->SetTransformedNode(transformationName, transformedNode); - body_[ix] = transformedNode; + auto const &body = Body(); + for (size_t ix = 0; ix < body.size(); ix++) { + if (auto *transformedNode = cb(body[ix]); body[ix] != transformedNode) { + body[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueBody(transformedNode, ix); } } } void ClassDefinition::Iterate(const NodeTraverser &cb) const { - if (ident_ != nullptr) { - cb(ident_); + auto const ident = GetHistoryNodeAs()->ident_; + if (ident != nullptr) { + cb(ident); } - if (typeParams_ != nullptr) { - cb(typeParams_); + auto const typeParams = GetHistoryNodeAs()->typeParams_; + if (typeParams != nullptr) { + cb(typeParams); } - if (superClass_ != nullptr) { - cb(superClass_); + auto const superClass = GetHistoryNodeAs()->superClass_; + if (superClass != nullptr) { + cb(superClass); } - if (superTypeParams_ != nullptr) { - cb(superTypeParams_); + auto const superTypeParams = GetHistoryNodeAs()->superTypeParams_; + if (superTypeParams != nullptr) { + cb(superTypeParams); } // Survives adding new elements to the end // NOLINTNEXTLINE(modernize-loop-convert) - for (size_t ix = 0; ix < implements_.size(); ix++) { - cb(implements_[ix]); + auto const &implements = GetHistoryNodeAs()->implements_; + for (auto implement : implements) { + cb(implement); } for (auto *it : VectorIterationGuard(Annotations())) { cb(it); } - if (ctor_ != nullptr) { - cb(ctor_); + auto const ctor = GetHistoryNodeAs()->ctor_; + if (ctor != nullptr) { + cb(ctor); } + auto const &body = GetHistoryNodeAs()->body_; // NOLINTNEXTLINE(modernize-loop-convert) - for (size_t ix = 0; ix < body_.size(); ix++) { - cb(body_[ix]); + for (size_t ix = 0; ix < body.size(); ix++) { + cb(body[ix]); } } void ClassDefinition::SetIdent(ir::Identifier *ident) noexcept { - ident_ = ident; - if (ident_ != nullptr) { - ident_->SetParent(this); + SETTER_FOR_CHILD_BODY(ClassDefinition, ident, ident_); + if (ident != nullptr) { + ident->SetParent(this); } } @@ -174,26 +203,27 @@ void ClassDefinition::Dump(ir::AstDumper *dumper) const auto propFilter = [](AstNode *prop) -> bool { return !prop->IsClassStaticBlock() || !prop->AsClassStaticBlock()->Function()->IsHidden(); }; - dumper->Add({{"id", AstDumper::Nullish(ident_)}, - {"typeParameters", AstDumper::Optional(typeParams_)}, - {"superClass", AstDumper::Nullish(superClass_)}, - {"superTypeParameters", AstDumper::Optional(superTypeParams_)}, - {"implements", implements_}, + auto ctor = GetHistoryNodeAs()->ctor_; + dumper->Add({{"id", AstDumper::Nullish(Ident())}, + {"typeParameters", AstDumper::Optional(TypeParams())}, + {"superClass", AstDumper::Nullish(SuperClass())}, + {"superTypeParameters", AstDumper::Optional(SuperTypeParams())}, + {"implements", Implements()}, {"annotations", AstDumper::Optional(Annotations())}, - {"constructor", AstDumper::Optional(ctor_)}, - {"body", body_, propFilter}}); + {"constructor", AstDumper::Optional(ctor)}, + {"body", Body(), propFilter}}); } void ClassDefinition::DumpGlobalClass(ir::SrcDumper *dumper) const { ES2PANDA_ASSERT(IsGlobal()); - for (auto elem : body_) { + for (auto elem : Body()) { if (elem->IsClassProperty()) { elem->Dump(dumper); dumper->Endl(); } } - for (auto elem : body_) { + for (auto elem : Body()) { if (elem->IsMethodDefinition()) { elem->Dump(dumper); dumper->Endl(); @@ -204,13 +234,14 @@ void ClassDefinition::DumpGlobalClass(ir::SrcDumper *dumper) const // This method is needed by OHOS CI code checker void ClassDefinition::DumpBody(ir::SrcDumper *dumper) const { + auto const body = Body(); dumper->Add(" {"); - if (!body_.empty()) { + if (!body.empty()) { dumper->IncrIndent(); dumper->Endl(); - for (auto elem : body_) { + for (auto elem : body) { elem->Dump(dumper); - if (elem == body_.back()) { + if (elem == body.back()) { dumper->DecrIndent(); } dumper->Endl(); @@ -270,7 +301,8 @@ bool ClassDefinition::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const void ClassDefinition::Dump(ir::SrcDumper *dumper) const { // NOTE: plugin API fails - if ((ident_->Name().StartsWith("$dynmodule")) || (ident_->Name().StartsWith("$jscall"))) { + auto const ident = Ident(); + if ((ident->Name().StartsWith("$dynmodule")) || (ident->Name().StartsWith("$jscall"))) { return; } @@ -292,19 +324,20 @@ void ClassDefinition::Dump(ir::SrcDumper *dumper) const DumpPrefix(dumper); ident_->Dump(dumper); - if (typeParams_ != nullptr) { + if (TypeParams() != nullptr) { dumper->Add("<"); - typeParams_->Dump(dumper); + TypeParams()->Dump(dumper); dumper->Add("> "); } - if (superClass_ != nullptr) { + if (SuperClass() != nullptr) { dumper->Add(" extends "); - superClass_->Dump(dumper); + SuperClass()->Dump(dumper); } - DumpItems(dumper, " implements ", implements_); - if (!IsDeclare() || !body_.empty()) { + DumpItems(dumper, " implements ", Implements()); + + if (!IsDeclare() || !Body().empty()) { DumpBody(dumper); } if (IsLocal()) { @@ -337,7 +370,7 @@ ClassDefinition *ClassDefinition::Construct(ArenaAllocator *allocator) { ArenaVector body {allocator->Adapter()}; return allocator->New(allocator, nullptr, std::move(body), ClassDefinitionModifiers::NONE, - ModifierFlags::NONE, Language::Id::COUNT); + ModifierFlags::NONE, Language::Id::COUNT, history_); } void ClassDefinition::CopyTo(AstNode *other) const @@ -366,6 +399,6 @@ void ClassDefinition::CopyTo(AstNode *other) const JsDocAllowed>::CopyTo(other); } -int ClassDefinition::classCounter_ = 0; +thread_local int ClassDefinition::classCounter_ = 0; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/base/classDefinition.h b/ets2panda/ir/base/classDefinition.h index 1539b6c3467015bd658922334902053eeb5a02c6..a9b1b288255e5793264dbf98077f5719e0d0aff9 100644 --- a/ets2panda/ir/base/classDefinition.h +++ b/ets2panda/ir/base/classDefinition.h @@ -21,6 +21,7 @@ #include "ir/srcDump.h" #include "ir/annotationAllowed.h" #include "ir/astNode.h" +#include "ir/astNodeHistory.h" #include "ir/expressions/identifier.h" #include "ir/jsDocAllowed.h" #include "ir/statements/annotationUsage.h" @@ -100,6 +101,7 @@ public: localPrefix_("$" + std::to_string(localIndex_)), exportedClasses_(body_.get_allocator()) { + EnableHistory(); } // CC-OFFNXT(G.FUN.01-CPP) solid logic explicit ClassDefinition(ArenaAllocator *allocator, Identifier *ident, ArenaVector &&body, @@ -116,6 +118,7 @@ public: localPrefix_("$" + std::to_string(localIndex_)), exportedClasses_(body_.get_allocator()) { + EnableHistory(); } explicit ClassDefinition(ArenaAllocator *allocator, Identifier *ident, ClassDefinitionModifiers modifiers, @@ -132,116 +135,128 @@ public: localPrefix_("$" + std::to_string(localIndex_)), exportedClasses_(body_.get_allocator()) { + EnableHistory(); } - [[nodiscard]] bool IsScopeBearer() const noexcept override + explicit ClassDefinition(ArenaAllocator *allocator, Identifier *ident, ArenaVector &&body, + ClassDefinitionModifiers modifiers, ModifierFlags flags, Language lang, + AstNodeHistory *history) + : JsDocAllowed>(AstNodeType::CLASS_DEFINITION, flags, allocator), + ident_(ident), + implements_(allocator->Adapter()), + body_(std::move(body)), + modifiers_(modifiers), + lang_(lang), + capturedVars_(allocator->Adapter()), + localVariableIsNeeded_(allocator->Adapter()), + localIndex_(classCounter_++), + localPrefix_("$" + std::to_string(localIndex_)), + exportedClasses_(body_.get_allocator()) { - return true; + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } - [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override + [[nodiscard]] bool IsScopeBearer() const noexcept override { - return scope_; + return true; } - void SetScope(varbinder::LocalScope *scope) + [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override { - ES2PANDA_ASSERT(scope_ == nullptr); - scope_ = scope; + RETURN_GET(ClassDefinition, scope_); } void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } [[nodiscard]] const Identifier *Ident() const noexcept { - return ident_; + RETURN_GET(ClassDefinition, ident_); } [[nodiscard]] Identifier *Ident() noexcept { - return ident_; + RETURN_GET(ClassDefinition, ident_); } void SetIdent(ir::Identifier *ident) noexcept; [[nodiscard]] const util::StringView &InternalName() const noexcept { - return internalName_; - } - - void SetInternalName(util::StringView internalName) noexcept - { - internalName_ = internalName; + RETURN_GET(ClassDefinition, internalName_); } [[nodiscard]] Expression *Super() noexcept { - return superClass_; + RETURN_GET(ClassDefinition, superClass_); } [[nodiscard]] const Expression *Super() const noexcept { - return superClass_; + RETURN_GET(ClassDefinition, superClass_); } void SetSuper(Expression *superClass) { - superClass_ = superClass; - if (superClass_ != nullptr) { - superClass_->SetParent(this); + SETTER_FOR_CHILD_BODY(ClassDefinition, superClass, superClass_); + if (newNode->superClass_ != nullptr) { + newNode->superClass_->SetParent(this); } } [[nodiscard]] bool IsGlobal() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::GLOBAL) != 0; + return (Modifiers() & ClassDefinitionModifiers::GLOBAL) != 0; } [[nodiscard]] bool IsLocal() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::LOCAL) != 0; + return (Modifiers() & ClassDefinitionModifiers::LOCAL) != 0; } [[nodiscard]] bool IsExtern() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::EXTERN) != 0; + return (Modifiers() & ClassDefinitionModifiers::EXTERN) != 0; } [[nodiscard]] bool IsFromExternal() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::FROM_EXTERNAL) != 0; + return (Modifiers() & ClassDefinitionModifiers::FROM_EXTERNAL) != 0; } [[nodiscard]] bool IsInner() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::INNER) != 0; + return (Modifiers() & ClassDefinitionModifiers::INNER) != 0; } [[nodiscard]] bool IsGlobalInitialized() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::GLOBAL_INITIALIZED) != 0; + return (Modifiers() & ClassDefinitionModifiers::GLOBAL_INITIALIZED) != 0; } [[nodiscard]] bool IsClassDefinitionChecked() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::CLASSDEFINITION_CHECKED) != 0; + return (Modifiers() & ClassDefinitionModifiers::CLASSDEFINITION_CHECKED) != 0; } [[nodiscard]] bool IsAnonymous() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::ANONYMOUS) != 0; + return (Modifiers() & ClassDefinitionModifiers::ANONYMOUS) != 0; } [[nodiscard]] bool IsIntEnumTransformed() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::INT_ENUM_TRANSFORMED) != 0; + return (Modifiers() & ClassDefinitionModifiers::INT_ENUM_TRANSFORMED) != 0; } [[nodiscard]] bool IsStringEnumTransformed() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::STRING_ENUM_TRANSFORMED) != 0; + return (Modifiers() & ClassDefinitionModifiers::STRING_ENUM_TRANSFORMED) != 0; } [[nodiscard]] bool IsEnumTransformed() const noexcept @@ -251,12 +266,12 @@ public: [[nodiscard]] bool IsNamespaceTransformed() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::NAMESPACE_TRANSFORMED) != 0; + return (Modifiers() & ClassDefinitionModifiers::NAMESPACE_TRANSFORMED) != 0; } [[nodiscard]] bool IsFromStruct() const noexcept { - return (modifiers_ & ClassDefinitionModifiers::FROM_STRUCT) != 0; + return (Modifiers() & ClassDefinitionModifiers::FROM_STRUCT) != 0; } [[nodiscard]] bool IsModule() const noexcept @@ -266,47 +281,42 @@ public: [[nodiscard]] es2panda::Language Language() const noexcept { - return lang_; + RETURN_GET(ClassDefinition, lang_); } void SetGlobalInitialized() noexcept { - modifiers_ |= ClassDefinitionModifiers::GLOBAL_INITIALIZED; + AddClassModifiers(ClassDefinitionModifiers::GLOBAL_INITIALIZED); } void SetInnerModifier() noexcept { - modifiers_ |= ClassDefinitionModifiers::INNER; + AddClassModifiers(ClassDefinitionModifiers::INNER); } void SetClassDefinitionChecked() noexcept { - modifiers_ |= ClassDefinitionModifiers::CLASSDEFINITION_CHECKED; + AddClassModifiers(ClassDefinitionModifiers::CLASSDEFINITION_CHECKED); } void SetAnonymousModifier() noexcept { - modifiers_ |= ClassDefinitionModifiers::ANONYMOUS; + AddClassModifiers(ClassDefinitionModifiers::ANONYMOUS); } void SetNamespaceTransformed() noexcept { - modifiers_ |= ClassDefinitionModifiers::NAMESPACE_TRANSFORMED; + AddClassModifiers(ClassDefinitionModifiers::NAMESPACE_TRANSFORMED); } void SetFromStructModifier() noexcept { - modifiers_ |= ClassDefinitionModifiers::FROM_STRUCT; + AddClassModifiers(ClassDefinitionModifiers::FROM_STRUCT); } [[nodiscard]] ClassDefinitionModifiers Modifiers() const noexcept { - return modifiers_; - } - - void SetModifiers(ClassDefinitionModifiers modifiers) noexcept - { - modifiers_ = modifiers; + RETURN_GET(ClassDefinition, modifiers_); } void AddProperties(ArenaVector &&body) @@ -315,64 +325,47 @@ public: prop->SetParent(this); } - body_.insert(body_.end(), body.begin(), body.end()); - } - - [[nodiscard]] ArenaVector &Body() noexcept - { - return body_; + auto newNode = GetOrCreateHistoryNode()->AsClassDefinition(); + CHANGEABLE_SET_CHILD(newNode); + newNode->body_.insert(newNode->body_.end(), body.begin(), body.end()); } [[nodiscard]] const ArenaVector &Body() const noexcept { - return body_; + RETURN_GET(ClassDefinition, body_); } [[nodiscard]] MethodDefinition *Ctor() noexcept { - return ctor_; - } - - void SetCtor(MethodDefinition *ctor) - { - ctor_ = ctor; - } - - [[nodiscard]] ArenaVector &Implements() noexcept - { - return implements_; + RETURN_GET(ClassDefinition, ctor_); } [[nodiscard]] const ArenaVector &Implements() const noexcept { - return implements_; + RETURN_GET(ClassDefinition, implements_); } [[nodiscard]] const ir::TSTypeParameterDeclaration *TypeParams() const noexcept { - return typeParams_; + RETURN_GET(ClassDefinition, typeParams_); } [[nodiscard]] ir::TSTypeParameterDeclaration *TypeParams() noexcept { - return typeParams_; - } - - void SetTypeParams(ir::TSTypeParameterDeclaration *typeParams) - { - typeParams_ = typeParams; + RETURN_GET(ClassDefinition, typeParams_); } const TSTypeParameterInstantiation *SuperTypeParams() const { - return superTypeParams_; + RETURN_GET(ClassDefinition, superTypeParams_); } TSTypeParameterInstantiation *SuperTypeParams() { - return superTypeParams_; + RETURN_GET(ClassDefinition, superTypeParams_); } + // TODO(ekkoruse) dangerous count for cache here [[nodiscard]] static int LocalTypeCounter() noexcept { return classCounter_; @@ -380,57 +373,51 @@ public: [[nodiscard]] int LocalIndex() const noexcept { - return localIndex_; + RETURN_GET(ClassDefinition, localIndex_); } [[nodiscard]] const std::string &LocalPrefix() const noexcept { - return localPrefix_; + RETURN_GET(ClassDefinition, localPrefix_); } bool CaptureVariable(varbinder::Variable *var) { - return capturedVars_.insert(var).second; + auto newNode = GetOrCreateHistoryNode()->AsClassDefinition(); + return newNode->capturedVars_.insert(var).second; } bool AddToLocalVariableIsNeeded(varbinder::Variable *var) { - return localVariableIsNeeded_.insert(var).second; + auto newNode = GetOrCreateHistoryNode()->AsClassDefinition(); + return newNode->localVariableIsNeeded_.insert(var).second; } bool IsLocalVariableNeeded(varbinder::Variable *var) const { - return localVariableIsNeeded_.find(var) != localVariableIsNeeded_.end(); + auto const newNode = GetHistoryNode()->AsClassDefinition(); + return newNode->localVariableIsNeeded_.find(var) != newNode->localVariableIsNeeded_.end(); } [[nodiscard]] const ArenaSet &CapturedVariables() const noexcept { - return capturedVars_; + RETURN_GET(ClassDefinition, capturedVars_); } bool EraseCapturedVariable(varbinder::Variable *var) { - return capturedVars_.erase(var) != 0; - } - - void SetOrigEnumDecl(ir::TSEnumDeclaration *enumDecl) - { - origEnumDecl_ = enumDecl; + auto newNode = GetOrCreateHistoryNode()->AsClassDefinition(); + return newNode->capturedVars_.erase(var) != 0; } ir::TSEnumDeclaration *OrigEnumDecl() const { - return origEnumDecl_; + RETURN_GET(ClassDefinition, origEnumDecl_); } ClassDeclaration *GetAnonClass() noexcept { - return anonClass_; - } - - void SetAnonClass(ClassDeclaration *anonClass) noexcept - { - anonClass_ = anonClass; + RETURN_GET(ClassDefinition, anonClass_); } const FunctionExpression *Ctor() const; @@ -472,26 +459,72 @@ public: void CleanUp() override { AstNode::CleanUp(); - modifiers_ &= ~(ClassDefinitionModifiers::CLASSDEFINITION_CHECKED); + ClearClassModifiers(ClassDefinitionModifiers::CLASSDEFINITION_CHECKED); } void AddToExportedClasses(const ir::ClassDeclaration *cls) { ES2PANDA_ASSERT(cls->IsExported()); - exportedClasses_.push_back(cls); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + newNode->exportedClasses_.emplace_back(cls); } [[nodiscard]] const ArenaVector &ExportedClasses() const noexcept { - return exportedClasses_; + RETURN_GET(ClassDefinition, exportedClasses_); } + void SetScope(varbinder::LocalScope *source); + void SetModifiers(ClassDefinitionModifiers source); + + void EmplaceBody(AstNode *source); + void ClearBody(); + void SetValueBody(AstNode *source, size_t index); + ArenaVector &Body(); + + void EmplaceImplements(TSClassImplements *source); + void ClearImplements(); + void SetValueImplements(TSClassImplements *source, size_t index); + ArenaVector &Implements(); + + void SetCtor(MethodDefinition *source); + void SetTypeParams(TSTypeParameterDeclaration *source); + void SetOrigEnumDecl(TSEnumDeclaration *source); + void SetAnonClass(ClassDeclaration *source); + void SetInternalName(util::StringView source); protected: ClassDefinition *Construct(ArenaAllocator *allocator) override; + void AddClassModifiers(ClassDefinitionModifiers const flags) noexcept + { + if (!All(Modifiers(), flags)) { + GetOrCreateHistoryNodeAs()->modifiers_ |= flags; + } + } + + void ClearClassModifiers(ClassDefinitionModifiers const flags) noexcept + { + if (Any(Modifiers(), flags)) { + GetOrCreateHistoryNodeAs()->modifiers_ &= ~flags; + } + } + void CopyTo(AstNode *other) const override; private: + void SetSuperClass(Expression *source); + void SetSuperTypeParams(TSTypeParameterInstantiation *source); + + [[nodiscard]] Expression *SuperClass() + { + RETURN_GET(ClassDefinition, superClass_); + } + + [[nodiscard]] const Expression *SuperClass() const + { + RETURN_GET(ClassDefinition, superClass_); + } + void CompileStaticFieldInitializers(compiler::PandaGen *pg, compiler::VReg classReg, const std::vector &staticComputedFieldKeys) const; @@ -517,7 +550,7 @@ private: ArenaSet localVariableIsNeeded_; TSEnumDeclaration *origEnumDecl_ {}; ClassDeclaration *anonClass_ {nullptr}; - static int classCounter_; + thread_local static int classCounter_; int localIndex_ {}; std::string localPrefix_ {}; ArenaVector exportedClasses_; diff --git a/ets2panda/ir/base/classElement.cpp b/ets2panda/ir/base/classElement.cpp index 9c54368dd8bc51eb3e3c3ddb35b153d5f850374b..7e24e227fc1787ff45f20a2f872add1a59a51cef 100644 --- a/ets2panda/ir/base/classElement.cpp +++ b/ets2panda/ir/base/classElement.cpp @@ -20,22 +20,33 @@ namespace ark::es2panda::ir { +SETTER_FOR_CHILD(ClassElement, OrigEnumMember, enumMember_, TSEnumMember *); +SETTER_FOR_CHILD(ClassElement, Key, key_, Expression *); + +SETTER_FOR_ARENAVECTOR_CHILD(ClassElement, Decorators, decorators_, Decorator *); + void ClassElement::SetValue(Expression *value) noexcept { + if (Value() == value) { + return; + } + if (value != nullptr) { value->SetParent(this); } - value_ = value; + SETTER_FOR_CHILD_BODY(ClassElement, value, value_); } Identifier *ClassElement::Id() noexcept { - return key_ != nullptr && key_->IsIdentifier() ? key_->AsIdentifier() : nullptr; + auto const key = GetHistoryNode()->AsClassElement()->key_; + return key != nullptr && key->IsIdentifier() ? key->AsIdentifier() : nullptr; } const Identifier *ClassElement::Id() const noexcept { - return key_ != nullptr && key_->IsIdentifier() ? key_->AsIdentifier() : nullptr; + auto const key = GetHistoryNode()->AsClassElement()->key_; + return key != nullptr && key->IsIdentifier() ? key->AsIdentifier() : nullptr; } bool ClassElement::IsPrivateElement() const noexcept @@ -44,7 +55,8 @@ bool ClassElement::IsPrivateElement() const noexcept return false; } - return key_->IsIdentifier() && key_->AsIdentifier()->IsPrivateIdent(); + auto const key = GetHistoryNode()->AsClassElement()->key_; + return key->IsIdentifier() && key->AsIdentifier()->IsPrivateIdent(); } void ClassElement::CopyTo(AstNode *other) const diff --git a/ets2panda/ir/base/classElement.h b/ets2panda/ir/base/classElement.h index fc372f8dc270498320a63006e8660b9f01f9872e..f8921840a408eb5e3db938b9f2529c67b2b94c93 100644 --- a/ets2panda/ir/base/classElement.h +++ b/ets2panda/ir/base/classElement.h @@ -38,6 +38,23 @@ public: decorators_(allocator->Adapter()), isComputed_(isComputed) { + EnableHistory(); + } + + explicit ClassElement(AstNodeType const elementType, Expression *const key, Expression *const value, + ModifierFlags const modifiers, ArenaAllocator *const allocator, bool const isComputed, + AstNodeHistory *history) + : TypedStatement(elementType, modifiers), + key_(key), + value_(value), + decorators_(allocator->Adapter()), + isComputed_(isComputed) + { + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } [[nodiscard]] Identifier *Id() noexcept; @@ -46,62 +63,58 @@ public: [[nodiscard]] Expression *Key() noexcept { - return key_; + RETURN_GET(ClassElement, key_); } [[nodiscard]] const Expression *Key() const noexcept { - return key_; + RETURN_GET(ClassElement, key_); } [[nodiscard]] Expression *Value() noexcept { - return value_; + RETURN_GET(ClassElement, value_); } void SetValue(Expression *value) noexcept; [[nodiscard]] const Expression *Value() const noexcept { - return value_; + RETURN_GET(ClassElement, value_); } [[nodiscard]] const TSEnumMember *OriginEnumMember() const noexcept { - return enumMember_; + RETURN_GET(ClassElement, enumMember_); } - void SetOrigEnumMember(ir::TSEnumMember *enumMember) - { - enumMember_ = enumMember; - } + void SetOrigEnumMember(ir::TSEnumMember *source); [[nodiscard]] bool IsPrivateElement() const noexcept; [[nodiscard]] const ArenaVector &Decorators() const noexcept { - return decorators_; - } - - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); + RETURN_GET(ClassElement, decorators_); } [[nodiscard]] bool IsComputed() const noexcept { - return isComputed_; + RETURN_GET(ClassElement, isComputed_); } void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = reinterpret_cast(GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + newNode->decorators_ = std::move(decorators); } void AddDecorator(ir::Decorator *const decorator) { if (decorator != nullptr) { - decorators_.emplace_back(decorator); + auto newNode = reinterpret_cast(GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + newNode->decorators_.emplace_back(decorator); } } @@ -114,8 +127,17 @@ public: void CopyTo(AstNode *other) const override; + void EmplaceDecorators(Decorator *source); + void ClearDecorators(); + void SetValueDecorators(Decorator *source, size_t index); + ArenaVector &Decorators(); + protected: friend class SizeOfNodeTest; + +protected: + void SetKey(Expression *source); + // NOLINTBEGIN(misc-non-private-member-variables-in-classes) Expression *key_; Expression *value_; diff --git a/ets2panda/ir/base/classProperty.cpp b/ets2panda/ir/base/classProperty.cpp index 03179884deaf6e26a60ecdc0b5e79683fc4a3e4b..6446fc8190e39c6648f88e1f2840da7dc8c895db 100644 --- a/ets2panda/ir/base/classProperty.cpp +++ b/ets2panda/ir/base/classProperty.cpp @@ -22,55 +22,68 @@ #include "compiler/lowering/util.h" namespace ark::es2panda::ir { + +SETTER_FOR_FIELD(ClassProperty, DefaultAccessModifier, isDefault_, bool); +SETTER_FOR_CHILD(ClassProperty, TypeAnnotation, typeAnnotation_, TypeNode *); + void ClassProperty::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (auto *transformedNode = cb(key_); key_ != transformedNode) { - key_->SetTransformedNode(transformationName, transformedNode); - key_ = transformedNode->AsExpression(); + auto *key = Key(); + if (key != nullptr) { + if (auto *transformedNode = cb(key); key != transformedNode) { + key->SetTransformedNode(transformationName, transformedNode); + SetKey(transformedNode->AsExpression()); + } } - if (value_ != nullptr) { - if (auto *transformedNode = cb(value_); value_ != transformedNode) { - value_->SetTransformedNode(transformationName, transformedNode); - value_ = transformedNode->AsExpression(); + auto *value = Value(); + if (value != nullptr) { + if (auto *transformedNode = cb(value); value != transformedNode) { + value->SetTransformedNode(transformationName, transformedNode); + SetValue(transformedNode->AsExpression()); } } - if (typeAnnotation_ != nullptr) { - if (auto *transformedNode = cb(typeAnnotation_); typeAnnotation_ != transformedNode) { - typeAnnotation_->SetTransformedNode(transformationName, transformedNode); - typeAnnotation_ = static_cast(transformedNode); + auto *typeAnnotation = TypeAnnotation(); + if (typeAnnotation != nullptr) { + if (auto *transformedNode = cb(typeAnnotation); typeAnnotation != transformedNode) { + typeAnnotation->SetTransformedNode(transformationName, transformedNode); + SetTypeAnnotation(static_cast(transformedNode)); } } - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - for (auto *&it : Annotations()) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); + auto const &annotations = Annotations(); + for (size_t ix = 0; ix < annotations.size(); ix++) { + if (auto *transformedNode = cb(annotations[ix]); annotations[ix] != transformedNode) { + annotations[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueAnnotations(transformedNode->AsAnnotationUsage(), ix); } } } void ClassProperty::Iterate(const NodeTraverser &cb) const { - cb(key_); + auto const key = GetHistoryNode()->AsClassProperty()->key_; + cb(key); - if (value_ != nullptr) { - cb(value_); + auto const value = GetHistoryNode()->AsClassProperty()->value_; + if (value != nullptr) { + cb(value); } - if (typeAnnotation_ != nullptr) { - cb(typeAnnotation_); + if (TypeAnnotation() != nullptr) { + cb(TypeAnnotation()); } - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } @@ -82,17 +95,17 @@ void ClassProperty::Iterate(const NodeTraverser &cb) const void ClassProperty::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "ClassProperty"}, - {"key", key_}, - {"value", AstDumper::Optional(value_)}, - {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(flags_))}, + {"key", Key()}, + {"value", AstDumper::Optional(Value())}, + {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(Modifiers()))}, {"static", IsStatic()}, {"readonly", IsReadonly()}, {"declare", IsDeclare()}, {"optional", IsOptionalDeclaration()}, - {"computed", isComputed_}, - {"typeAnnotation", AstDumper::Optional(typeAnnotation_)}, + {"computed", IsComputed()}, + {"typeAnnotation", AstDumper::Optional(TypeAnnotation())}, {"definite", IsDefinite()}, - {"decorators", decorators_}, + {"decorators", Decorators()}, {"annotations", AstDumper::Optional(Annotations())}}); } @@ -219,8 +232,8 @@ void ClassProperty::Dump(ir::SrcDumper *dumper) const } DumpPrefix(dumper); - if (key_ != nullptr) { - key_->Dump(dumper); + if (Key() != nullptr) { + Key()->Dump(dumper); } if (IsOptionalDeclaration()) { @@ -229,14 +242,14 @@ void ClassProperty::Dump(ir::SrcDumper *dumper) const if (typeAnnotation_ != nullptr && !dumper->IsDeclgen()) { dumper->Add(": "); - typeAnnotation_->Dump(dumper); + TypeAnnotation()->Dump(dumper); } DumpCheckerTypeForDeclGen(dumper); if (value_ != nullptr && !dumper->IsDeclgen()) { dumper->Add(" = "); - value_->Dump(dumper); + Value()->Dump(dumper); } dumper->Add(";"); @@ -265,11 +278,11 @@ checker::VerifiedType ClassProperty::Check(checker::ETSChecker *checker) ClassProperty *ClassProperty::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const key = key_->Clone(allocator, nullptr)->AsExpression(); - auto *const value = value_ != nullptr ? value_->Clone(allocator, nullptr)->AsExpression() : nullptr; - auto *const typeAnnotation = typeAnnotation_ != nullptr ? typeAnnotation_->Clone(allocator, nullptr) : nullptr; + auto *const key = Key()->Clone(allocator, nullptr)->AsExpression(); + auto *const value = Value() != nullptr ? Value()->Clone(allocator, nullptr)->AsExpression() : nullptr; + auto *const typeAnnotation = TypeAnnotation() != nullptr ? TypeAnnotation()->Clone(allocator, nullptr) : nullptr; - auto *const clone = allocator->New(key, value, typeAnnotation, flags_, allocator, isComputed_); + auto *const clone = allocator->New(key, value, typeAnnotation, Modifiers(), allocator, IsComputed()); if (parent != nullptr) { clone->SetParent(parent); @@ -277,7 +290,7 @@ ClassProperty *ClassProperty::Clone(ArenaAllocator *const allocator, AstNode *co key->SetParent(clone); if (value != nullptr) { - value->SetTsType(value_->TsType()); + value->SetTsType(Value()->TsType()); value->SetParent(clone); } if (typeAnnotation != nullptr) { @@ -285,7 +298,7 @@ ClassProperty *ClassProperty::Clone(ArenaAllocator *const allocator, AstNode *co typeAnnotation->SetParent(clone); } - for (auto *const decorator : decorators_) { + for (auto *const decorator : Decorators()) { clone->AddDecorator(decorator->Clone(allocator, clone)); } @@ -297,7 +310,7 @@ ClassProperty *ClassProperty::Clone(ArenaAllocator *const allocator, AstNode *co clone->SetAnnotations(std::move(annotationUsages)); } - clone->SetRange(range_); + clone->SetRange(Range()); return clone; } diff --git a/ets2panda/ir/base/classProperty.h b/ets2panda/ir/base/classProperty.h index 9725118c5768c391a30a843346f9b0d86d1423ba..b63251a418525b5c20f8d259229a32f7af400283 100644 --- a/ets2panda/ir/base/classProperty.h +++ b/ets2panda/ir/base/classProperty.h @@ -47,23 +47,17 @@ public: [[nodiscard]] bool IsDefaultAccessModifier() const noexcept { - return isDefault_; + RETURN_GET(ClassProperty, isDefault_); } - void SetDefaultAccessModifier(bool isDefault) - { - isDefault_ = isDefault; - } + void SetDefaultAccessModifier(bool source); [[nodiscard]] TypeNode *TypeAnnotation() const noexcept { - return typeAnnotation_; + RETURN_GET(ClassProperty, typeAnnotation_); } - void SetTypeAnnotation(TypeNode *typeAnnotation) noexcept - { - typeAnnotation_ = typeAnnotation; - } + void SetTypeAnnotation(TypeNode *source); [[nodiscard]] PrivateFieldKind ToPrivateFieldKind(bool const isStatic) const override { diff --git a/ets2panda/ir/base/classStaticBlock.cpp b/ets2panda/ir/base/classStaticBlock.cpp index d58703d0b7caba8e2d83492a1ac157024241f261..9f330dda451b087f61bfe7f90ba8929632e596dd 100644 --- a/ets2panda/ir/base/classStaticBlock.cpp +++ b/ets2panda/ir/base/classStaticBlock.cpp @@ -30,20 +30,22 @@ namespace ark::es2panda::ir { void ClassStaticBlock::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - if (auto *transformedNode = cb(value_); value_ != transformedNode) { - value_->SetTransformedNode(transformationName, transformedNode); - value_ = transformedNode->AsExpression(); + auto const value = Value(); + if (auto *transformedNode = cb(value); value != transformedNode) { + value->SetTransformedNode(transformationName, transformedNode); + SetValue(transformedNode->AsExpression()); } } void ClassStaticBlock::Iterate(const NodeTraverser &cb) const { - cb(value_); + auto const value = reinterpret_cast(GetHistoryNode())->value_; + cb(value); } void ClassStaticBlock::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ClassStaticBlock"}, {"value", value_}}); + dumper->Add({{"type", "ClassStaticBlock"}, {"value", Value()}}); } void ClassStaticBlock::Dump([[maybe_unused]] ir::SrcDumper *dumper) const @@ -73,12 +75,12 @@ checker::VerifiedType ClassStaticBlock::Check(checker::ETSChecker *checker) ir::ScriptFunction *ClassStaticBlock::Function() { - return value_->AsFunctionExpression()->Function(); + return Value()->AsFunctionExpression()->Function(); } const ir::ScriptFunction *ClassStaticBlock::Function() const { - return value_->AsFunctionExpression()->Function(); + return Value()->AsFunctionExpression()->Function(); } const util::StringView &ClassStaticBlock::Name() const diff --git a/ets2panda/ir/base/classStaticBlock.h b/ets2panda/ir/base/classStaticBlock.h index a1a1030b757e57649e0ecddff8eae8fcb4eae2ae..9410b1e592aa1a6bdb1fd5d4cb8c5cd7f15a17e2 100644 --- a/ets2panda/ir/base/classStaticBlock.h +++ b/ets2panda/ir/base/classStaticBlock.h @@ -26,6 +26,7 @@ public: explicit ClassStaticBlock(Expression *value, ArenaAllocator *allocator) : ClassElement(AstNodeType::CLASS_STATIC_BLOCK, nullptr, value, ModifierFlags::NONE, allocator, false) { + EnableHistory(); } PrivateFieldKind ToPrivateFieldKind([[maybe_unused]] bool isStatic) const override @@ -51,6 +52,16 @@ public: v->Accept(this); } + ClassStaticBlock *Construct(ArenaAllocator *allocator) override + { + return allocator->New(nullptr, allocator); + } + + void CopyTo(AstNode *other) const override + { + ClassElement::CopyTo(other); + }; + private: }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/base/methodDefinition.cpp b/ets2panda/ir/base/methodDefinition.cpp index c4a19ecc866d17cbed75c77a5ea85872e3433db3..aa7adc9b3182e327d7827a955531b786f470aaed 100644 --- a/ets2panda/ir/base/methodDefinition.cpp +++ b/ets2panda/ir/base/methodDefinition.cpp @@ -24,19 +24,28 @@ namespace ark::es2panda::ir { +SETTER_FOR_FIELD(MethodDefinition, DefaultAccessModifier, isDefault_, bool); + +SETTER_FOR_CHILD(MethodDefinition, BaseOverloadMethod, baseOverloadMethod_, MethodDefinition *); +SETTER_FOR_CHILD(MethodDefinition, AsyncPairMethod, asyncPairMethod_, MethodDefinition *); + +SETTER_FOR_ARENAVECTOR_CHILD(MethodDefinition, Overloads, overloads_, MethodDefinition *); + ScriptFunction *MethodDefinition::Function() { - return value_->IsFunctionExpression() ? value_->AsFunctionExpression()->Function() : nullptr; + auto const value = Value(); + return value->IsFunctionExpression() ? value->AsFunctionExpression()->Function() : nullptr; } const ScriptFunction *MethodDefinition::Function() const { - return value_->IsFunctionExpression() ? value_->AsFunctionExpression()->Function() : nullptr; + auto const value = Value(); + return value->IsFunctionExpression() ? value->AsFunctionExpression()->Function() : nullptr; } PrivateFieldKind MethodDefinition::ToPrivateFieldKind(bool const isStatic) const { - switch (kind_) { + switch (Kind()) { case MethodDefinitionKind::METHOD: { return isStatic ? PrivateFieldKind::STATIC_METHOD : PrivateFieldKind::METHOD; } @@ -54,57 +63,65 @@ PrivateFieldKind MethodDefinition::ToPrivateFieldKind(bool const isStatic) const void MethodDefinition::ResolveReferences(const NodeTraverser &cb) const { - cb(key_); - cb(value_); + auto key = GetHistoryNode()->AsMethodDefinition()->key_; + auto value = GetHistoryNode()->AsMethodDefinition()->value_; + cb(key); + cb(value); - for (auto *it : VectorIterationGuard(overloads_)) { + for (auto *it : VectorIterationGuard(Overloads())) { cb(it); } - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } } void MethodDefinition::Iterate(const NodeTraverser &cb) const { - cb(key_); - cb(value_); + auto key = GetHistoryNode()->AsMethodDefinition()->key_; + auto value = GetHistoryNode()->AsMethodDefinition()->value_; + cb(key); + cb(value); - for (auto *it : overloads_) { + for (auto *it : Overloads()) { if (it->Parent() == this) { cb(it); } } - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } } void MethodDefinition::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (auto *transformedNode = cb(key_); key_ != transformedNode) { - key_->SetTransformedNode(transformationName, transformedNode); - key_ = transformedNode->AsExpression(); + auto *key = Key(); + if (auto *transformedNode = cb(key); key != transformedNode) { + key->SetTransformedNode(transformationName, transformedNode); + SetKey(transformedNode->AsExpression()); } - if (auto *transformedNode = cb(value_); value_ != transformedNode) { - value_->SetTransformedNode(transformationName, transformedNode); - value_ = transformedNode->AsExpression(); + auto *value = Value(); + if (auto *transformedNode = cb(value); value != transformedNode) { + value->SetTransformedNode(transformationName, transformedNode); + SetValue(transformedNode->AsExpression()); } - for (auto *&it : VectorIterationGuard(overloads_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsMethodDefinition(); + auto const &overloads = Overloads(); + for (size_t ix = 0; ix < overloads.size(); ix++) { + if (auto *transformedNode = cb(overloads[ix]); overloads[ix] != transformedNode) { + overloads[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueOverloads(transformedNode->AsMethodDefinition(), ix); } } - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } } @@ -113,7 +130,7 @@ void MethodDefinition::Dump(ir::AstDumper *dumper) const { const char *kind = nullptr; - switch (kind_) { + switch (Kind()) { case MethodDefinitionKind::CONSTRUCTOR: { kind = "constructor"; break; @@ -148,15 +165,15 @@ void MethodDefinition::Dump(ir::AstDumper *dumper) const } dumper->Add({{"type", "MethodDefinition"}, - {"key", key_}, + {"key", Key()}, {"kind", kind}, - {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(flags_))}, + {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(Modifiers()))}, {"static", IsStatic()}, {"optional", IsOptionalDeclaration()}, - {"computed", isComputed_}, - {"value", value_}, - {"overloads", overloads_}, - {"decorators", decorators_}}); + {"computed", IsComputed()}, + {"value", Value()}, + {"overloads", Overloads()}, + {"decorators", Decorators()}}); } void MethodDefinition::DumpModifierPrefix(ir::SrcDumper *dumper) const @@ -303,22 +320,24 @@ void MethodDefinition::Dump(ir::SrcDumper *dumper) const return; } - for (auto method : overloads_) { + for (auto method : Overloads()) { method->Dump(dumper); dumper->Endl(); } - for (auto *anno : value_->AsFunctionExpression()->Function()->Annotations()) { + auto value = Value(); + for (auto *anno : value->AsFunctionExpression()->Function()->Annotations()) { anno->Dump(dumper); } DumpPrefix(dumper); - if (key_ != nullptr) { - key_->Dump(dumper); + auto key = Key(); + if (key != nullptr) { + key->Dump(dumper); } - if (value_ != nullptr) { - value_->Dump(dumper); + if (value != nullptr) { + value->Dump(dumper); } } @@ -344,9 +363,9 @@ checker::VerifiedType MethodDefinition::Check(checker::ETSChecker *checker) MethodDefinition *MethodDefinition::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const key = key_->Clone(allocator, nullptr)->AsExpression(); - auto *const value = value_->Clone(allocator, nullptr)->AsExpression(); - auto *const clone = allocator->New(kind_, key, value, flags_, allocator, isComputed_); + auto *const key = Key()->Clone(allocator, nullptr)->AsExpression(); + auto *const value = Value()->Clone(allocator, nullptr)->AsExpression(); + auto *const clone = allocator->New(Kind(), key, value, Modifiers(), allocator, IsComputed()); if (parent != nullptr) { clone->SetParent(parent); @@ -355,13 +374,13 @@ MethodDefinition *MethodDefinition::Clone(ArenaAllocator *const allocator, AstNo key->SetParent(clone); value->SetParent(clone); - for (auto *const decorator : decorators_) { + for (auto *const decorator : Decorators()) { clone->AddDecorator(decorator->Clone(allocator, clone)); } - clone->baseOverloadMethod_ = baseOverloadMethod_; + clone->SetBaseOverloadMethod(BaseOverloadMethod()); - for (auto *const overloads : overloads_) { + for (auto *const overloads : Overloads()) { clone->AddOverload(overloads->Clone(allocator, clone)); } @@ -372,19 +391,16 @@ void MethodDefinition::InitializeOverloadInfo() { ES2PANDA_ASSERT(this->Function() != nullptr); - overloadInfo_ = {this->Function()->Signature()->MinArgCount(), - this->Function()->Signature()->ArgCount(), - false, - this->IsDeclare(), - (this->Function()->Signature()->RestVar() != nullptr), - this->Function()->Signature()->ReturnType()->IsETSVoidType()}; + SetOverloadInfo({this->Function()->Signature()->MinArgCount(), this->Function()->Signature()->ArgCount(), false, + this->IsDeclare(), (this->Function()->Signature()->RestVar() != nullptr), + this->Function()->Signature()->ReturnType()->IsETSVoidType()}); } void MethodDefinition::ResetOverloads() { - auto baseOverloadMethod = baseOverloadMethod_; - baseOverloadMethod_ = nullptr; - for (auto *overload : overloads_) { + auto baseOverloadMethod = BaseOverloadMethod(); + SetBaseOverloadMethod(nullptr); + for (auto *overload : Overloads()) { overload->CleanUp(); } ClearOverloads(); @@ -413,7 +429,8 @@ void MethodDefinition::ResetOverloads() } } - body.emplace_back(this); + parent->IsClassDefinition() ? parent->AsClassDefinition()->Body().push_back(this) + : parent->AsTSInterfaceBody()->Body().push_back(this); } void MethodDefinition::CleanUp() diff --git a/ets2panda/ir/base/methodDefinition.h b/ets2panda/ir/base/methodDefinition.h index 22b53211293c7bbc0986e00ee7a719a93c133621..dd6b8e1e25b4f1d54ea71782a10898f63947149e 100644 --- a/ets2panda/ir/base/methodDefinition.h +++ b/ets2panda/ir/base/methodDefinition.h @@ -66,113 +66,143 @@ public: baseOverloadMethod_(nullptr), asyncPairMethod_(nullptr) { + EnableHistory(); + } + + explicit MethodDefinition(MethodDefinitionKind const kind, Expression *const key, Expression *const value, + ModifierFlags const modifiers, ArenaAllocator *const allocator, bool const isComputed, + AstNodeHistory *history) + : ClassElement(AstNodeType::METHOD_DEFINITION, key, value, modifiers, allocator, isComputed), + kind_(kind), + overloads_(allocator->Adapter()), + baseOverloadMethod_(nullptr), + asyncPairMethod_(nullptr) + { + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } // NOTE (csabahurton): these friend relationships can be removed once there are getters for private fields + // TODO (Ekkoruse): why, may cause problems to cache friend class checker::ETSAnalyzer; MethodDefinitionKind Kind() const { - return kind_; + RETURN_GET(MethodDefinition, kind_); } [[nodiscard]] bool IsConstructor() const noexcept { - return kind_ == MethodDefinitionKind::CONSTRUCTOR; + return Kind() == MethodDefinitionKind::CONSTRUCTOR; } [[nodiscard]] bool IsMethod() const noexcept { - return kind_ == MethodDefinitionKind::METHOD; + return Kind() == MethodDefinitionKind::METHOD; } [[nodiscard]] bool IsExtensionMethod() const noexcept { - return (kind_ == MethodDefinitionKind::EXTENSION_METHOD) || (kind_ == MethodDefinitionKind::EXTENSION_GET) || - (kind_ == MethodDefinitionKind::EXTENSION_SET); + auto const kind = Kind(); + return (kind == MethodDefinitionKind::EXTENSION_METHOD) || (kind == MethodDefinitionKind::EXTENSION_GET) || + (kind == MethodDefinitionKind::EXTENSION_SET); } [[nodiscard]] bool IsGetter() const noexcept { - return kind_ == MethodDefinitionKind::GET; + return Kind() == MethodDefinitionKind::GET; } [[nodiscard]] bool IsSetter() const noexcept { - return kind_ == MethodDefinitionKind::SET; + return Kind() == MethodDefinitionKind::SET; } [[nodiscard]] bool IsDefaultAccessModifier() const noexcept { - return isDefault_; + RETURN_GET(MethodDefinition, isDefault_); } - void SetDefaultAccessModifier(bool isDefault) - { - isDefault_ = isDefault; - } + void SetDefaultAccessModifier(bool source); [[nodiscard]] const OverloadsT &Overloads() const noexcept { - return overloads_; + RETURN_GET(MethodDefinition, overloads_); } [[nodiscard]] const MethodDefinition *BaseOverloadMethod() const noexcept { - return baseOverloadMethod_; + RETURN_GET(MethodDefinition, baseOverloadMethod_); } [[nodiscard]] MethodDefinition *BaseOverloadMethod() noexcept { - return baseOverloadMethod_; + RETURN_GET(MethodDefinition, baseOverloadMethod_); } [[nodiscard]] const MethodDefinition *AsyncPairMethod() const noexcept { - return asyncPairMethod_; + RETURN_GET(MethodDefinition, asyncPairMethod_); } [[nodiscard]] MethodDefinition *AsyncPairMethod() noexcept { - return asyncPairMethod_; + RETURN_GET(MethodDefinition, asyncPairMethod_); } [[nodiscard]] OverloadInfo &GetOverloadInfo() noexcept { - return overloadInfo_; + auto newNode = this->GetOrCreateHistoryNode()->AsMethodDefinition(); + return newNode->overloadInfo_; } - void SetOverloads(OverloadsT &&overloads) + [[nodiscard]] const OverloadInfo &GetOverloadInfo() const noexcept { - overloads_ = std::move(overloads); + RETURN_GET(MethodDefinition, overloadInfo_); } - void ClearOverloads() + void SetOverloadInfo(OverloadInfo &&overloadInfo) { - overloads_.clear(); + auto newNode = this->GetOrCreateHistoryNode()->AsMethodDefinition(); + newNode->overloadInfo_ = overloadInfo; } - void AddOverload(MethodDefinition *const overload) + void SetOverloadInfo(OverloadInfo &overloadInfo) { - ES2PANDA_ASSERT(overload != nullptr); - overloads_.emplace_back(overload); - overload->Function()->AddFlag((ir::ScriptFunctionFlags::OVERLOAD)); - overload->SetBaseOverloadMethod(this); + auto newNode = this->GetOrCreateHistoryNode()->AsMethodDefinition(); + newNode->overloadInfo_ = overloadInfo; } - void SetBaseOverloadMethod(MethodDefinition *const baseOverloadMethod) + void SetOverloads(OverloadsT &&overloads) { - baseOverloadMethod_ = baseOverloadMethod; + auto newNode = this->GetOrCreateHistoryNode()->AsMethodDefinition(); + CHANGEABLE_SET_CHILD(newNode); + newNode->overloads_ = std::move(overloads); } - void SetAsyncPairMethod(MethodDefinition *const method) + void ClearOverloads(); + + void AddOverload(MethodDefinition *const overload) { - asyncPairMethod_ = method; + ES2PANDA_ASSERT(overload != nullptr); + auto newNode = this->GetOrCreateHistoryNode()->AsMethodDefinition(); + CHANGEABLE_SET_CHILD(newNode); + newNode->overloads_.emplace_back(overload); + overload->Function()->AddFlag((ir::ScriptFunctionFlags::OVERLOAD)); + overload->SetBaseOverloadMethod(this); } + void SetBaseOverloadMethod(MethodDefinition *const source); + + void SetAsyncPairMethod(MethodDefinition *const source); + [[nodiscard]] bool HasOverload(MethodDefinition *overload) noexcept { - return std::find(overloads_.begin(), overloads_.end(), overload) != overloads_.end(); + auto const overloads = Overloads(); + return std::find(overloads.begin(), overloads.end(), overload) != overloads.end(); } ScriptFunction *Function(); @@ -201,6 +231,10 @@ public: void CleanUp() override; + void EmplaceOverloads(MethodDefinition *source); + void SetValueOverloads(MethodDefinition *source, size_t index); + ArenaVector &Overloads(); + protected: MethodDefinition *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; diff --git a/ets2panda/ir/base/scriptFunction.cpp b/ets2panda/ir/base/scriptFunction.cpp index 396d22d082e862af1ca1a1d1254ef8c4f8898712..ae218b497f45bd9c271e908cfe77472b15b0b941 100644 --- a/ets2panda/ir/base/scriptFunction.cpp +++ b/ets2panda/ir/base/scriptFunction.cpp @@ -25,6 +25,15 @@ namespace ark::es2panda::ir { +SETTER_FOR_CHILD(ScriptFunction, Body, body_, AstNode *); + +SETTER_FOR_FIELD(ScriptFunction, Signature, signature_, checker::Signature *); +SETTER_FOR_FIELD(ScriptFunction, Scope, scope_, varbinder::FunctionScope *); +SETTER_FOR_FIELD(ScriptFunction, PreferredReturnType, preferredReturnType_, checker::Type *); + +SETTER_FOR_ARENAVECTOR_CHILD(ScriptFunction, Params, irSignature_.Params(), Expression *); +SETTER_FOR_ARENAVECTOR_CHILD(ScriptFunction, ReturnStatements, returnStatements_, ReturnStatement *); + ScriptFunction::ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data) : JsDocAllowed>(AstNodeType::SCRIPT_FUNCTION, data.flags, allocator), irSignature_(std::move(data.signature)), @@ -44,13 +53,40 @@ ScriptFunction::ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&d if (auto *typeParams = irSignature_.TypeParams(); typeParams != nullptr) { typeParams->SetParent(this); } + EnableHistory(); +} + +ScriptFunction::ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data, AstNodeHistory *history) + : JsDocAllowed>(AstNodeType::SCRIPT_FUNCTION, data.flags, allocator), + irSignature_(std::move(data.signature)), + body_(data.body), + funcFlags_(data.funcFlags), + lang_(data.lang), + returnStatements_(allocator->Adapter()) +{ + for (auto *param : irSignature_.Params()) { + param->SetParent(this); + } + + if (auto *returnType = irSignature_.ReturnType(); returnType != nullptr) { + returnType->SetParent(this); + } + + if (auto *typeParams = irSignature_.TypeParams(); typeParams != nullptr) { + typeParams->SetParent(this); + } + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } std::size_t ScriptFunction::FormalParamsLength() const noexcept { std::size_t length = 0U; - for (const auto *param : irSignature_.Params()) { + for (const auto *param : Params()) { if (param->IsRestElement() || param->IsAssignmentPattern()) { break; } @@ -63,8 +99,8 @@ std::size_t ScriptFunction::FormalParamsLength() const noexcept void ScriptFunction::SetIdent(Identifier *id) noexcept { - id_ = id; - id_->SetParent(this); + SETTER_FOR_CHILD_BODY(ScriptFunction, id, id_); + id->SetParent(this); } ScriptFunction *ScriptFunction::Clone(ArenaAllocator *allocator, AstNode *parent) @@ -80,7 +116,7 @@ ScriptFunction *ScriptFunction::Clone(ArenaAllocator *allocator, AstNode *parent auto *res = util::NodeAllocator::ForceSetParent( allocator, allocator, ScriptFunctionData { - body_ != nullptr ? body_->Clone(allocator, nullptr) : nullptr, + Body() != nullptr ? Body()->Clone(allocator, nullptr) : nullptr, FunctionSignature { TypeParams() != nullptr ? TypeParams()->Clone(allocator, nullptr)->AsTSTypeParameterDeclaration() : nullptr, @@ -88,7 +124,7 @@ ScriptFunction *ScriptFunction::Clone(ArenaAllocator *allocator, AstNode *parent ReturnTypeAnnotation() != nullptr ? ReturnTypeAnnotation()->Clone(allocator, nullptr)->AsTypeNode() : nullptr, HasReceiver()}, - funcFlags_, flags_, lang_}); + Flags(), Modifiers(), Language()}); res->SetParent(parent); res->SetAnnotations(std::move(annotationUsages)); return res; @@ -96,38 +132,38 @@ ScriptFunction *ScriptFunction::Clone(ArenaAllocator *allocator, AstNode *parent void ScriptFunction::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (id_ != nullptr) { - if (auto *transformedNode = cb(id_); id_ != transformedNode) { - id_->SetTransformedNode(transformationName, transformedNode); - id_ = transformedNode->AsIdentifier(); + auto const id = Id(); + if (id != nullptr) { + if (auto *transformedNode = cb(id); id != transformedNode) { + id->SetTransformedNode(transformationName, transformedNode); + SetIdent(transformedNode->AsIdentifier()); } } - irSignature_.TransformChildren(cb, transformationName); + GetOrCreateHistoryNode()->AsScriptFunction()->irSignature_.TransformChildren(cb, transformationName); - if (body_ != nullptr) { - if (auto *transformedNode = cb(body_); body_ != transformedNode) { - body_->SetTransformedNode(transformationName, transformedNode); - body_ = transformedNode; + auto const &body = Body(); + if (body != nullptr) { + if (auto *transformedNode = cb(body); body != transformedNode) { + body->SetTransformedNode(transformationName, transformedNode); + SetBody(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ScriptFunction::Iterate(const NodeTraverser &cb) const { - if (id_ != nullptr) { - cb(id_); + auto id = GetHistoryNode()->AsScriptFunction()->id_; + if (id != nullptr) { + cb(id); } - irSignature_.Iterate(cb); - if (body_ != nullptr) { - cb(body_); + GetHistoryNode()->AsScriptFunction()->irSignature_.Iterate(cb); + + auto body = GetHistoryNode()->AsScriptFunction()->body_; + if (body != nullptr) { + cb(body); } for (auto *it : VectorIterationGuard(Annotations())) { cb(it); @@ -136,7 +172,8 @@ void ScriptFunction::Iterate(const NodeTraverser &cb) const void ScriptFunction::SetReturnTypeAnnotation(TypeNode *node) noexcept { - irSignature_.SetReturnType(node); + auto newNode = GetOrCreateHistoryNode()->AsScriptFunction(); + newNode->irSignature_.SetReturnType(node); if (node != nullptr) { node->SetParent(this); } @@ -151,15 +188,15 @@ void ScriptFunction::Dump(ir::AstDumper *dumper) const throwMarker = "rethrows"; } dumper->Add({{"type", "ScriptFunction"}, - {"id", AstDumper::Nullish(id_)}, + {"id", AstDumper::Nullish(Id())}, {"generator", IsGenerator()}, {"async", IsAsyncFunc()}, - {"expression", ((funcFlags_ & ir::ScriptFunctionFlags::EXPRESSION) != 0)}, - {"params", irSignature_.Params()}, - {"returnType", AstDumper::Optional(irSignature_.ReturnType())}, - {"typeParameters", AstDumper::Optional(irSignature_.TypeParams())}, + {"expression", ((Flags() & ir::ScriptFunctionFlags::EXPRESSION) != 0)}, + {"params", Params()}, + {"returnType", AstDumper::Optional(ReturnTypeAnnotation())}, + {"typeParameters", AstDumper::Optional(TypeParams())}, {"declare", AstDumper::Optional(IsDeclare())}, - {"body", AstDumper::Optional(body_)}, + {"body", AstDumper::Optional(Body())}, {"annotations", AstDumper::Optional(Annotations())}, {"throwMarker", AstDumper::Optional(throwMarker)}}); } diff --git a/ets2panda/ir/base/scriptFunction.h b/ets2panda/ir/base/scriptFunction.h index c301d7d459a5d121d3009090241f253cd00746c4..fb79de343ebb480dbada79014ad25c6c3199268b 100644 --- a/ets2panda/ir/base/scriptFunction.h +++ b/ets2panda/ir/base/scriptFunction.h @@ -56,136 +56,129 @@ public: explicit ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data); + explicit ScriptFunction(ArenaAllocator *allocator, ScriptFunctionData &&data, AstNodeHistory *history); + [[nodiscard]] const Identifier *Id() const noexcept { - return id_; + RETURN_GET(ScriptFunction, id_); } [[nodiscard]] Identifier *Id() noexcept { - return id_; + RETURN_GET(ScriptFunction, id_); } [[nodiscard]] const checker::Signature *Signature() const noexcept { - return signature_; + RETURN_GET(ScriptFunction, signature_); } [[nodiscard]] checker::Signature *Signature() noexcept { - return signature_; + RETURN_GET(ScriptFunction, signature_); } [[nodiscard]] const ArenaVector &Params() const noexcept { - return irSignature_.Params(); + RETURN_GET(ScriptFunction, irSignature_.Params()); } - [[nodiscard]] ArenaVector &Params() noexcept - { - return irSignature_.Params(); - } + [[nodiscard]] ArenaVector &Params(); const ArenaVector &ReturnStatements() const { - return returnStatements_; + RETURN_GET(ScriptFunction, returnStatements_); } - ArenaVector &ReturnStatements() - { - return returnStatements_; - } + [[nodiscard]] ArenaVector &ReturnStatements(); [[nodiscard]] const TSTypeParameterDeclaration *TypeParams() const noexcept { - return irSignature_.TypeParams(); + RETURN_GET(ScriptFunction, irSignature_.TypeParams()); } [[nodiscard]] TSTypeParameterDeclaration *TypeParams() noexcept { - return irSignature_.TypeParams(); + return GetOrCreateHistoryNode()->AsScriptFunction()->irSignature_.TypeParams(); } [[nodiscard]] const AstNode *Body() const noexcept { - return body_; + RETURN_GET(ScriptFunction, body_); } [[nodiscard]] AstNode *Body() noexcept { - return body_; + RETURN_GET(ScriptFunction, body_); } void AddReturnStatement(ReturnStatement *returnStatement) { - returnStatements_.push_back(returnStatement); + EmplaceReturnStatements(returnStatement); } - void SetBody(AstNode *body) noexcept - { - body_ = body; - } + void SetBody(AstNode *source); [[nodiscard]] const TypeNode *ReturnTypeAnnotation() const noexcept { - return irSignature_.ReturnType(); + RETURN_GET(ScriptFunction, irSignature_.ReturnType()); } [[nodiscard]] TypeNode *ReturnTypeAnnotation() noexcept { - return irSignature_.ReturnType(); + return GetOrCreateHistoryNode()->AsScriptFunction()->irSignature_.ReturnType(); } void SetReturnTypeAnnotation(TypeNode *node) noexcept; [[nodiscard]] bool IsEntryPoint() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::ENTRY_POINT) != 0; + return (Flags() & ir::ScriptFunctionFlags::ENTRY_POINT) != 0; } [[nodiscard]] bool IsGenerator() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::GENERATOR) != 0; + return (Flags() & ir::ScriptFunctionFlags::GENERATOR) != 0; } [[nodiscard]] bool IsAsyncFunc() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::ASYNC) != 0; + return (Flags() & ir::ScriptFunctionFlags::ASYNC) != 0; } [[nodiscard]] bool IsAsyncImplFunc() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::ASYNC_IMPL) != 0; + return (Flags() & ir::ScriptFunctionFlags::ASYNC_IMPL) != 0; } [[nodiscard]] bool IsArrow() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::ARROW) != 0; + return (Flags() & ir::ScriptFunctionFlags::ARROW) != 0; } [[nodiscard]] bool IsOverload() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::OVERLOAD) != 0; + return (Flags() & ir::ScriptFunctionFlags::OVERLOAD) != 0; } [[nodiscard]] bool IsExternalOverload() const { - return (funcFlags_ & ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD) != 0; + return (Flags() & ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD) != 0; } [[nodiscard]] bool IsConstructor() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::CONSTRUCTOR) != 0; + return (Flags() & ir::ScriptFunctionFlags::CONSTRUCTOR) != 0; } [[nodiscard]] bool IsGetter() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::GETTER) != 0; + return (Flags() & ir::ScriptFunctionFlags::GETTER) != 0; } [[nodiscard]] bool IsSetter() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::SETTER) != 0; + return (Flags() & ir::ScriptFunctionFlags::SETTER) != 0; } [[nodiscard]] bool IsExtensionAccessor() const noexcept @@ -195,72 +188,72 @@ public: [[nodiscard]] bool IsMethod() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::METHOD) != 0; + return (Flags() & ir::ScriptFunctionFlags::METHOD) != 0; } [[nodiscard]] bool IsProxy() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::PROXY) != 0; + return (Flags() & ir::ScriptFunctionFlags::PROXY) != 0; } [[nodiscard]] bool IsStaticBlock() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::STATIC_BLOCK) != 0; + return (Flags() & ir::ScriptFunctionFlags::STATIC_BLOCK) != 0; } [[nodiscard]] bool IsEnum() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::ENUM) != 0; + return (Flags() & ir::ScriptFunctionFlags::ENUM) != 0; } [[nodiscard]] bool IsHidden() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::HIDDEN) != 0; + return (Flags() & ir::ScriptFunctionFlags::HIDDEN) != 0; } [[nodiscard]] bool IsExternal() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::EXTERNAL) != 0; + return (Flags() & ir::ScriptFunctionFlags::EXTERNAL) != 0; } [[nodiscard]] bool IsImplicitSuperCallNeeded() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED) != 0; + return (Flags() & ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED) != 0; } [[nodiscard]] bool HasBody() const noexcept { - return body_ != nullptr; + return Body() != nullptr; } [[nodiscard]] bool HasRestParameter() const noexcept { - return signature_->RestVar() != nullptr; + return Signature()->RestVar() != nullptr; } [[nodiscard]] bool HasReturnStatement() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::HAS_RETURN) != 0; + return (Flags() & ir::ScriptFunctionFlags::HAS_RETURN) != 0; } [[nodiscard]] bool HasThrowStatement() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::HAS_THROW) != 0; + return (Flags() & ir::ScriptFunctionFlags::HAS_THROW) != 0; } [[nodiscard]] bool IsThrowing() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::THROWS) != 0; + return (Flags() & ir::ScriptFunctionFlags::THROWS) != 0; } [[nodiscard]] bool IsRethrowing() const noexcept { - return (funcFlags_ & ir::ScriptFunctionFlags::RETHROWS) != 0; + return (Flags() & ir::ScriptFunctionFlags::RETHROWS) != 0; } [[nodiscard]] bool IsDynamic() const noexcept { - return lang_.IsDynamic(); + return Language().IsDynamic(); } // Note: This method has been written into CAPI, cannot remove it simply. @@ -271,34 +264,30 @@ public: [[nodiscard]] ir::ScriptFunctionFlags Flags() const noexcept { - return funcFlags_; + RETURN_GET(ScriptFunction, funcFlags_); } [[nodiscard]] bool HasReceiver() const noexcept { - return irSignature_.HasReceiver(); + RETURN_GET(ScriptFunction, irSignature_.HasReceiver()); } void SetIdent(Identifier *id) noexcept; - void SetSignature(checker::Signature *signature) noexcept - { - signature_ = signature; - } + void SetSignature(checker::Signature *source); void AddFlag(ir::ScriptFunctionFlags flags) noexcept { - funcFlags_ |= flags; + if (!All(Flags(), flags)) { + GetOrCreateHistoryNode()->AsScriptFunction()->funcFlags_ |= flags; + } } void ClearFlag(ir::ScriptFunctionFlags flags) noexcept { - funcFlags_ &= (~flags); - } - - void AddModifier(ir::ModifierFlags flags) noexcept - { - flags_ |= flags; + if (Any(Flags(), flags)) { + GetOrCreateHistoryNode()->AsScriptFunction()->funcFlags_ &= ~flags; + } } [[nodiscard]] std::size_t FormalParamsLength() const noexcept; @@ -310,37 +299,31 @@ public: [[nodiscard]] varbinder::FunctionScope *Scope() const noexcept override { - return scope_; + RETURN_GET(ScriptFunction, scope_); } - void SetScope(varbinder::FunctionScope *scope) noexcept - { - scope_ = scope; - } + void SetScope(varbinder::FunctionScope *source); void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } [[nodiscard]] es2panda::Language Language() const noexcept { - return lang_; + RETURN_GET(ScriptFunction, lang_); } - void SetPreferredReturnType(checker::Type *preferredReturnType) noexcept - { - preferredReturnType_ = preferredReturnType; - } + void SetPreferredReturnType(checker::Type *source); [[nodiscard]] checker::Type *GetPreferredReturnType() noexcept { - return preferredReturnType_; + RETURN_GET(ScriptFunction, preferredReturnType_); } [[nodiscard]] checker::Type const *GetPreferredReturnType() const noexcept { - return preferredReturnType_; + RETURN_GET(ScriptFunction, preferredReturnType_); } [[nodiscard]] ScriptFunction *Clone(ArenaAllocator *allocator, AstNode *parent) override; @@ -363,9 +346,16 @@ public: void CleanUp() override { AstNode::CleanUp(); - signature_ = nullptr; - preferredReturnType_ = nullptr; + SetSignature(nullptr); + SetPreferredReturnType(nullptr); } + void EmplaceReturnStatements(ReturnStatement *source); + void ClearReturnStatements(); + void SetValueReturnStatements(ReturnStatement *source, size_t index); + + void EmplaceParams(Expression *source); + void ClearParams(); + void SetValueParams(Expression *source, size_t index); protected: ScriptFunction *Construct(ArenaAllocator *allocator) override; diff --git a/ets2panda/ir/base/spreadElement.cpp b/ets2panda/ir/base/spreadElement.cpp index 1f69ae5286064ab92351f29537edad94f3e8af5c..a8417930319850984ece9b9b5ab10864e48fab4d 100644 --- a/ets2panda/ir/base/spreadElement.cpp +++ b/ets2panda/ir/base/spreadElement.cpp @@ -143,7 +143,7 @@ void SpreadElement::Dump(ir::SrcDumper *dumper) const dumper->Add("..."); argument_->Dump(dumper); auto type = TypeAnnotation(); - if (type != nullptr) { + if (type != nullptr && type->IsValidInCurrentPhase()) { dumper->Add(": "); type->Dump(dumper); } diff --git a/ets2panda/ir/base/spreadElement.h b/ets2panda/ir/base/spreadElement.h index 803e8e32a4de5404e5b17e7ea0c14ed28c4abcb6..f9eefb502c5e3b282ce2c8bfe3d530fc0d64354e 100644 --- a/ets2panda/ir/base/spreadElement.h +++ b/ets2panda/ir/base/spreadElement.h @@ -59,11 +59,6 @@ public: return decorators_; } - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); - } - void AddDecorators(ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/ets/etsFunctionType.cpp b/ets2panda/ir/ets/etsFunctionType.cpp index da4e93b20cfb8845d2cff05be1bf53c282ece6d1..6204a9090954f435c17f84ec8fcbe8a000894d58 100644 --- a/ets2panda/ir/ets/etsFunctionType.cpp +++ b/ets2panda/ir/ets/etsFunctionType.cpp @@ -24,12 +24,7 @@ namespace ark::es2panda::ir { void ETSFunctionType::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { signature_.TransformChildren(cb, transformationName); - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSFunctionType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsImportDeclaration.h b/ets2panda/ir/ets/etsImportDeclaration.h index 4abdaff764848f0e02e20160318a4f8edc3fefea..7f7e56683b221a2bc6ac9471678f65c41a3fe307 100644 --- a/ets2panda/ir/ets/etsImportDeclaration.h +++ b/ets2panda/ir/ets/etsImportDeclaration.h @@ -44,31 +44,32 @@ public: void SetImportMetadata(util::ImportFlags importFlags, Language::Id lang, std::string_view resolvedSource, std::string_view declPath, std::string_view ohmUrl) { - importMetadata_.importFlags = importFlags; - importMetadata_.lang = lang; - importMetadata_.resolvedSource = resolvedSource; - importMetadata_.declPath = declPath; - importMetadata_.ohmUrl = ohmUrl; + auto node = GetOrCreateHistoryNode()->AsETSImportDeclaration(); + node->importMetadata_.importFlags = importFlags; + node->importMetadata_.lang = lang; + node->importMetadata_.resolvedSource = resolvedSource; + node->importMetadata_.declPath = declPath; + node->importMetadata_.ohmUrl = ohmUrl; } es2panda::Language Language() const { - return es2panda::Language {importMetadata_.lang}; + return es2panda::Language {ImportMetadata().lang}; } std::string_view DeclPath() const { - return importMetadata_.declPath; + return ImportMetadata().declPath; } std::string_view OhmUrl() const { - return importMetadata_.ohmUrl; + return ImportMetadata().ohmUrl; } bool IsValid() const { - return (Source()->Str() != ERROR_LITERAL) && importMetadata_.IsValid(); + return (Source()->Str() != ERROR_LITERAL) && ImportMetadata().IsValid(); } bool IsPureDynamic() const @@ -76,24 +77,24 @@ public: return IsValid() && DeclPath().empty() && Language().IsDynamic(); } - util::StringView &AssemblerName() + void SetAssemblerName(util::StringView assemblerName) { - return assemblerName_; + GetOrCreateHistoryNode()->AsETSImportDeclaration()->assemblerName_ = assemblerName; } const util::StringView &AssemblerName() const { - return assemblerName_; + return GetHistoryNode()->AsETSImportDeclaration()->assemblerName_; } std::string_view ResolvedSource() const { - return importMetadata_.resolvedSource; + return ImportMetadata().resolvedSource; } - const auto &ImportMetadata() const + const util::ImportPathManager::ImportMetadata &ImportMetadata() const { - return importMetadata_; + return GetHistoryNode()->AsETSImportDeclaration()->importMetadata_; } void Accept(ASTVisitorT *v) override @@ -101,6 +102,22 @@ public: v->Accept(this); } + ETSImportDeclaration *Construct(ArenaAllocator *allocator) override + { + ArenaVector specifiers(allocator->Adapter()); + return allocator->New(nullptr, std::move(specifiers)); + } + + void CopyTo(AstNode *other) const override + { + auto otherImpl = other->AsETSImportDeclaration(); + + otherImpl->importMetadata_ = importMetadata_; + otherImpl->assemblerName_ = assemblerName_; + + ImportDeclaration::CopyTo(other); + }; + private: util::ImportPathManager::ImportMetadata importMetadata_; util::StringView assemblerName_ {}; diff --git a/ets2panda/ir/ets/etsModule.cpp b/ets2panda/ir/ets/etsModule.cpp index 3fea029e815d4d9281ec27a992d00be6be3fdede..4891a53166698946c5d4127c5b5516ef41841d92 100644 --- a/ets2panda/ir/ets/etsModule.cpp +++ b/ets2panda/ir/ets/etsModule.cpp @@ -34,7 +34,7 @@ void ETSModule::Dump(ir::SrcDumper *dumper) const } dumper->Add("namespace "); - ident_->Dump(dumper); + Ident()->Dump(dumper); dumper->Add(" {"); dumper->IncrIndent(); } @@ -67,6 +67,7 @@ void ETSModule::CopyTo(AstNode *other) const otherImpl->ident_ = ident_; otherImpl->flag_ = flag_; otherImpl->program_ = program_; + otherImpl->globalClass_ = globalClass_; JsDocAllowed>::CopyTo(other); } diff --git a/ets2panda/ir/ets/etsModule.h b/ets2panda/ir/ets/etsModule.h index 0c967d8d245aad5bd2186f5f7de6f507ec0be7b8..79d948a3096d6a66c75d1fdc553dabe9c2848b5f 100644 --- a/ets2panda/ir/ets/etsModule.h +++ b/ets2panda/ir/ets/etsModule.h @@ -54,47 +54,80 @@ public: program_(program) { type_ = AstNodeType::ETS_MODULE; + EnableHistory(); + } + + explicit ETSModule(ArenaAllocator *allocator, ArenaVector &&statementList, Identifier *ident, + ModuleFlag flag, parser::Program *program, AstNodeHistory *history) + : JsDocAllowed>(allocator, std::move(statementList)), + ident_(ident), + flag_(flag), + program_(program) + { + type_ = AstNodeType::ETS_MODULE; + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } ir::Identifier *Ident() { - return ident_; + RETURN_GET(ETSModule, ident_); } const ir::Identifier *Ident() const { - return ident_; + RETURN_GET(ETSModule, ident_); } parser::Program *Program() { - return program_; + RETURN_GET(ETSModule, program_); + } + + const ir::ClassDefinition *GlobalClass() const + { + RETURN_GET(ETSModule, globalClass_); + } + + ir::ClassDefinition *GlobalClass() + { + RETURN_GET(ETSModule, globalClass_); + } + + void SetGlobalClass(ir::ClassDefinition *globalClass) + { + if (globalClass != GlobalClass()) { + GetOrCreateHistoryNode()->AsETSModule()->globalClass_ = globalClass; + } } [[nodiscard]] bool IsETSScript() const noexcept { - return (flag_ & ModuleFlag::ETSSCRIPT) != 0; + return (ModuleFlags() & ModuleFlag::ETSSCRIPT) != 0; } [[nodiscard]] bool IsNamespace() const noexcept { - return (flag_ & ModuleFlag::NAMESPACE) != 0; + return (ModuleFlags() & ModuleFlag::NAMESPACE) != 0; } [[nodiscard]] bool IsNamespaceChainLastNode() const noexcept { - return (flag_ & ModuleFlag::NAMESPACE_CHAIN_LAST_NODE) != 0; + return (ModuleFlags() & ModuleFlag::NAMESPACE_CHAIN_LAST_NODE) != 0; } void SetNamespaceChainLastNode() noexcept { ES2PANDA_ASSERT(IsNamespace()); - flag_ |= ModuleFlag::NAMESPACE_CHAIN_LAST_NODE; + AddModuleFlag(ModuleFlag::NAMESPACE_CHAIN_LAST_NODE); } const parser::Program *Program() const { - return program_; + RETURN_GET(ETSModule, program_) } void Dump(ir::SrcDumper *dumper) const override; void Accept(ASTVisitorT *v) override @@ -107,9 +140,29 @@ public: private: friend class SizeOfNodeTest; + ModuleFlag ModuleFlags() const + { + RETURN_GET(ETSModule, flag_); + } + + void AddModuleFlag(ModuleFlag flag) noexcept + { + if (!All(ModuleFlags(), flag)) { + GetOrCreateHistoryNode()->AsETSModule()->flag_ |= flag; + } + } + + void ClearModuleFlag(ModuleFlag flag) noexcept + { + if (Any(ModuleFlags(), flag)) { + GetOrCreateHistoryNode()->AsETSModule()->flag_ &= ~flag; + } + } + Identifier *ident_; ModuleFlag flag_; parser::Program *program_; + ir::ClassDefinition *globalClass_ {}; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ets/etsNeverType.cpp b/ets2panda/ir/ets/etsNeverType.cpp index 79284dd1f72e3bf37538f07f13547c9a08a41bbd..3f40e3475075ab2a1bc7613410322b7179f01387 100644 --- a/ets2panda/ir/ets/etsNeverType.cpp +++ b/ets2panda/ir/ets/etsNeverType.cpp @@ -21,12 +21,7 @@ namespace ark::es2panda::ir { void ETSNeverType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSNeverType::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsNullishTypes.cpp b/ets2panda/ir/ets/etsNullishTypes.cpp index e3e9e7983678fd1e341b4ef1e288950800243472..0957d162a44a9493faa2b1eeae1410807b7609ee 100644 --- a/ets2panda/ir/ets/etsNullishTypes.cpp +++ b/ets2panda/ir/ets/etsNullishTypes.cpp @@ -21,12 +21,7 @@ namespace ark::es2panda::ir { void ETSUndefinedType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSUndefinedType::Iterate([[maybe_unused]] const NodeTraverser &cb) const @@ -92,12 +87,7 @@ ETSUndefinedType *ETSUndefinedType::Clone(ArenaAllocator *allocator, AstNode *pa void ETSNullType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSNullType::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsParameterExpression.cpp b/ets2panda/ir/ets/etsParameterExpression.cpp index 382a8a6f11307c438870e9c002f40da30a43ce66..161641b271b5542d48900117f939b393c785a780 100644 --- a/ets2panda/ir/ets/etsParameterExpression.cpp +++ b/ets2panda/ir/ets/etsParameterExpression.cpp @@ -22,8 +22,18 @@ namespace ark::es2panda::ir { +SETTER_FOR_FIELD(ETSParameterExpression, RequiredParams, extraValue_, size_t); +SETTER_FOR_FIELD(ETSParameterExpression, LexerSaved, savedLexer_, util::StringView); +SETTER_FOR_CHILD(ETSParameterExpression, Spread, spread_, SpreadElement *); + ETSParameterExpression::ETSParameterExpression(AnnotatedExpression *const identOrSpread, bool isOptional, ArenaAllocator *const allocator) + : ETSParameterExpression(identOrSpread, isOptional, allocator, nullptr) +{ +} + +ETSParameterExpression::ETSParameterExpression(AnnotatedExpression *const identOrSpread, bool isOptional, + ArenaAllocator *const allocator, AstNodeHistory *history) : AnnotationAllowed(AstNodeType::ETS_PARAMETER_EXPRESSION, allocator) { SetOptional(isOptional); @@ -43,125 +53,141 @@ ETSParameterExpression::ETSParameterExpression(AnnotatedExpression *const identO } else { ES2PANDA_UNREACHABLE(); } + + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } ETSParameterExpression::ETSParameterExpression(AnnotatedExpression *const identOrSpread, ir::Expression *initializer, ArenaAllocator *const allocator) + : ETSParameterExpression(identOrSpread, initializer, allocator, nullptr) +{ +} + +ETSParameterExpression::ETSParameterExpression(AnnotatedExpression *const identOrSpread, ir::Expression *initializer, + ArenaAllocator *const allocator, AstNodeHistory *history) : ETSParameterExpression(identOrSpread, true, allocator) { SetInitializer(initializer); + + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } const util::StringView &ETSParameterExpression::Name() const noexcept { - return ident_->Name(); + return Ident()->Name(); } const Identifier *ETSParameterExpression::Ident() const noexcept { - return ident_; + RETURN_GET(ETSParameterExpression, ident_); } Identifier *ETSParameterExpression::Ident() noexcept { - return ident_; + RETURN_GET(ETSParameterExpression, ident_); } const SpreadElement *ETSParameterExpression::RestParameter() const noexcept { - return spread_; + RETURN_GET(ETSParameterExpression, spread_); } SpreadElement *ETSParameterExpression::RestParameter() noexcept { - return spread_; + RETURN_GET(ETSParameterExpression, spread_); } const Expression *ETSParameterExpression::Initializer() const noexcept { - return initializer_; + RETURN_GET(ETSParameterExpression, initializer_); } Expression *ETSParameterExpression::Initializer() noexcept { - return initializer_; + RETURN_GET(ETSParameterExpression, initializer_); } varbinder::Variable *ETSParameterExpression::Variable() const noexcept { - return ident_->Variable(); + return Ident()->Variable(); } TypeNode const *ETSParameterExpression::TypeAnnotation() const noexcept { - return !IsRestParameter() ? ident_->TypeAnnotation() : spread_->TypeAnnotation(); + return !IsRestParameter() ? Ident()->TypeAnnotation() : Spread()->TypeAnnotation(); } TypeNode *ETSParameterExpression::TypeAnnotation() noexcept { - return !IsRestParameter() ? ident_->TypeAnnotation() : spread_->TypeAnnotation(); + return !IsRestParameter() ? Ident()->TypeAnnotation() : Spread()->TypeAnnotation(); } void ETSParameterExpression::SetTypeAnnotation(TypeNode *typeNode) noexcept { - !IsRestParameter() ? ident_->SetTsTypeAnnotation(typeNode) : spread_->SetTsTypeAnnotation(typeNode); + !IsRestParameter() ? Ident()->SetTsTypeAnnotation(typeNode) : Spread()->SetTsTypeAnnotation(typeNode); } void ETSParameterExpression::SetVariable(varbinder::Variable *const variable) noexcept { - ident_->SetVariable(variable); -} - -void ETSParameterExpression::SetLexerSaved(util::StringView s) noexcept -{ - savedLexer_ = s; + Ident()->SetVariable(variable); } util::StringView ETSParameterExpression::LexerSaved() const noexcept { - return savedLexer_; + RETURN_GET(ETSParameterExpression, savedLexer_); } void ETSParameterExpression::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { + auto const spread = Spread(); + auto const ident = Ident(); + auto newNode = GetOrCreateHistoryNodeAs(); if (IsRestParameter()) { - if (auto *transformedNode = cb(spread_); spread_ != transformedNode) { - spread_->SetTransformedNode(transformationName, transformedNode); - spread_ = transformedNode->AsRestElement(); + if (auto *transformedNode = cb(spread); spread != transformedNode) { + spread->SetTransformedNode(transformationName, transformedNode); + SetSpread(transformedNode->AsRestElement()); } - ident_ = spread_->Argument()->AsIdentifier(); + CHANGEABLE_SET_CHILD(newNode); + newNode->ident_ = Spread()->Argument()->AsIdentifier(); } else { - if (auto *transformedNode = cb(ident_); ident_ != transformedNode) { - ident_->SetTransformedNode(transformationName, transformedNode); - ident_ = transformedNode->AsIdentifier(); + if (auto *transformedNode = cb(ident); ident != transformedNode) { + ident->SetTransformedNode(transformationName, transformedNode); + SetIdent(transformedNode->AsIdentifier()); } } - if (initializer_ != nullptr) { - if (auto *transformedNode = cb(initializer_); initializer_ != transformedNode) { - initializer_->SetTransformedNode(transformationName, transformedNode); - initializer_ = transformedNode->AsExpression(); + auto const initializer = Initializer(); + if (initializer != nullptr) { + if (auto *transformedNode = cb(initializer); initializer != transformedNode) { + initializer->SetTransformedNode(transformationName, transformedNode); + SetInitializer(transformedNode->AsExpression()); } } - for (auto *&it : Annotations()) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSParameterExpression::Iterate(const NodeTraverser &cb) const { if (IsRestParameter()) { - cb(spread_); + auto const spread = GetHistoryNode()->AsETSParameterExpression()->spread_; + cb(spread); } else { - cb(ident_); + auto const ident = GetHistoryNode()->AsETSParameterExpression()->ident_; + cb(ident); } - if (initializer_ != nullptr) { - cb(initializer_); + auto const initializer = GetHistoryNode()->AsETSParameterExpression()->initializer_; + if (initializer != nullptr) { + cb(initializer); } for (auto *it : Annotations()) { @@ -173,12 +199,12 @@ void ETSParameterExpression::Dump(ir::AstDumper *const dumper) const { if (!IsRestParameter()) { dumper->Add({{"type", "ETSParameterExpression"}, - {"name", ident_}, - {"initializer", AstDumper::Optional(initializer_)}, + {"name", Ident()}, + {"initializer", AstDumper::Optional(Initializer())}, {"annotations", AstDumper::Optional(Annotations())}}); } else { dumper->Add({{"type", "ETSParameterExpression"}, - {"rest parameter", spread_}, + {"rest parameter", Spread()}, {"annotations", AstDumper::Optional(Annotations())}}); } } @@ -190,23 +216,25 @@ void ETSParameterExpression::Dump(ir::SrcDumper *const dumper) const } if (IsRestParameter()) { - spread_->Dump(dumper); + Spread()->Dump(dumper); } else { - if (ident_ != nullptr) { + auto const ident = Ident(); + auto const initializer = Initializer(); + if (ident != nullptr) { ES2PANDA_ASSERT(ident_->IsAnnotatedExpression()); - ident_->Dump(dumper); - if (isOptional_ && initializer_ == nullptr) { + ident->Dump(dumper); + if (IsOptional() && initializer == nullptr) { dumper->Add("?"); } - auto typeAnnotation = ident_->AsAnnotatedExpression()->TypeAnnotation(); + auto typeAnnotation = ident->AsAnnotatedExpression()->TypeAnnotation(); if (typeAnnotation != nullptr) { dumper->Add(": "); typeAnnotation->Dump(dumper); } } - if (initializer_ != nullptr) { + if (initializer != nullptr) { dumper->Add(" = "); - initializer_->Dump(dumper); + initializer->Dump(dumper); } } } @@ -233,14 +261,14 @@ checker::VerifiedType ETSParameterExpression::Check(checker::ETSChecker *const c ETSParameterExpression *ETSParameterExpression::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const identOrSpread = spread_ != nullptr ? spread_->Clone(allocator, nullptr)->AsAnnotatedExpression() - : ident_->Clone(allocator, nullptr)->AsAnnotatedExpression(); + auto *const identOrSpread = Spread() != nullptr ? Spread()->Clone(allocator, nullptr)->AsAnnotatedExpression() + : Ident()->Clone(allocator, nullptr)->AsAnnotatedExpression(); auto *const initializer = - initializer_ != nullptr ? initializer_->Clone(allocator, nullptr)->AsExpression() : nullptr; + Initializer() != nullptr ? Initializer()->Clone(allocator, nullptr)->AsExpression() : nullptr; - auto *const clone = initializer_ != nullptr + auto *const clone = Initializer() != nullptr ? allocator->New(identOrSpread, initializer, allocator) - : allocator->New(identOrSpread, isOptional_, allocator); + : allocator->New(identOrSpread, IsOptional(), allocator); identOrSpread->SetParent(clone); if (initializer != nullptr) { @@ -251,7 +279,7 @@ ETSParameterExpression *ETSParameterExpression::Clone(ArenaAllocator *const allo clone->SetParent(parent); } - clone->SetRequiredParams(extraValue_); + clone->SetRequiredParams(GetRequiredParams()); if (!Annotations().empty()) { ArenaVector annotationUsages {allocator->Adapter()}; diff --git a/ets2panda/ir/ets/etsParameterExpression.h b/ets2panda/ir/ets/etsParameterExpression.h index a38f760c793ff653d24e7e5edfa41a74573c16ca..ae9cb4e2f2a6ac731a3a789198a4db5bb6445f08 100644 --- a/ets2panda/ir/ets/etsParameterExpression.h +++ b/ets2panda/ir/ets/etsParameterExpression.h @@ -38,9 +38,15 @@ public: explicit ETSParameterExpression(AnnotatedExpression *identOrSpread, bool isOptional, ArenaAllocator *const allocator); + explicit ETSParameterExpression(AnnotatedExpression *identOrSpread, bool isOptional, + ArenaAllocator *const allocator, AstNodeHistory *history); + explicit ETSParameterExpression(AnnotatedExpression *identOrSpread, ir::Expression *initializer, ArenaAllocator *const allocator); + explicit ETSParameterExpression(AnnotatedExpression *identOrSpread, ir::Expression *initializer, + ArenaAllocator *const allocator, AstNodeHistory *history); + [[nodiscard]] const util::StringView &Name() const noexcept; [[nodiscard]] const Identifier *Ident() const noexcept; @@ -48,8 +54,8 @@ public: void SetIdent(Identifier *ident) noexcept { - ident_ = ident; - ident_->SetParent(this); + SETTER_FOR_CHILD_BODY(ETSParameterExpression, ident, ident_); + ident->SetParent(this); } [[nodiscard]] const SpreadElement *RestParameter() const noexcept; @@ -58,7 +64,7 @@ public: [[nodiscard]] const Expression *Initializer() const noexcept; [[nodiscard]] Expression *Initializer() noexcept; - void SetLexerSaved(util::StringView s) noexcept; + void SetLexerSaved(util::StringView s); [[nodiscard]] util::StringView LexerSaved() const noexcept; [[nodiscard]] varbinder::Variable *Variable() const noexcept; @@ -71,35 +77,32 @@ public: [[nodiscard]] bool IsOptional() const noexcept { - return isOptional_; + RETURN_GET(ETSParameterExpression, isOptional_); } void SetOptional(bool value) noexcept { - isOptional_ = value; - ES2PANDA_ASSERT(isOptional_ || initializer_ == nullptr); + SETTER_FOR_CHILD_BODY(ETSParameterExpression, value, isOptional_); + ES2PANDA_ASSERT(IsOptional() || Initializer() == nullptr); } void SetInitializer(Expression *initExpr) noexcept { - initializer_ = initExpr; - ES2PANDA_ASSERT(isOptional_ || initializer_ == nullptr); + SETTER_FOR_CHILD_BODY(ETSParameterExpression, initExpr, initializer_); + ES2PANDA_ASSERT(IsOptional() || Initializer() == nullptr); } [[nodiscard]] bool IsRestParameter() const noexcept { - return spread_ != nullptr; + return Spread() != nullptr; } [[nodiscard]] std::size_t GetRequiredParams() const noexcept { - return extraValue_; + RETURN_GET(ETSParameterExpression, extraValue_); } - void SetRequiredParams(std::size_t const value) noexcept - { - extraValue_ = value; - } + void SetRequiredParams(std::size_t const source); [[nodiscard]] ETSParameterExpression *Clone(ArenaAllocator *allocator, AstNode *parent) override; @@ -122,6 +125,18 @@ public: private: friend class SizeOfNodeTest; + SpreadElement *Spread() noexcept + { + RETURN_GET(ETSParameterExpression, spread_); + } + + const SpreadElement *Spread() const noexcept + { + RETURN_GET(ETSParameterExpression, spread_); + } + + void SetSpread(SpreadElement *source); + Identifier *ident_; Expression *initializer_ = nullptr; SpreadElement *spread_ = nullptr; diff --git a/ets2panda/ir/ets/etsPrimitiveType.cpp b/ets2panda/ir/ets/etsPrimitiveType.cpp index c18f74350262d4994bce708bdd606cfcf57c1501..20708e3048dfc0ffd4a4c4b8358b91da7f769f3e 100644 --- a/ets2panda/ir/ets/etsPrimitiveType.cpp +++ b/ets2panda/ir/ets/etsPrimitiveType.cpp @@ -24,12 +24,7 @@ namespace ark::es2panda::ir { void ETSPrimitiveType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSPrimitiveType::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsReExportDeclaration.cpp b/ets2panda/ir/ets/etsReExportDeclaration.cpp index c5df1d644b18f37e84ca394510cba76380762455..647819871b5457dcd6e3188354a1fddd83637b5d 100644 --- a/ets2panda/ir/ets/etsReExportDeclaration.cpp +++ b/ets2panda/ir/ets/etsReExportDeclaration.cpp @@ -19,6 +19,8 @@ namespace ark::es2panda::ir { +SETTER_FOR_CHILD(ETSReExportDeclaration, ETSImportDeclarations, etsImportDeclarations_, ETSImportDeclaration *); + ETSReExportDeclaration::ETSReExportDeclaration(ETSImportDeclaration *etsImportDeclarations, const std::vector &userPaths, util::StringView programPath, ArenaAllocator *allocator) @@ -30,26 +32,29 @@ ETSReExportDeclaration::ETSReExportDeclaration(ETSImportDeclaration *etsImportDe for (const auto &path : userPaths) { userPaths_.emplace_back(util::UString(path, allocator).View()); } + EnableHistory(); } void ETSReExportDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (etsImportDeclarations_ != nullptr) { - if (auto *transformedNode = cb(etsImportDeclarations_); etsImportDeclarations_ != transformedNode) { - etsImportDeclarations_->SetTransformedNode(transformationName, transformedNode); - etsImportDeclarations_ = transformedNode->AsETSImportDeclaration(); + auto const etsImportDecl = GetETSImportDeclarations(); + if (etsImportDecl != nullptr) { + if (auto *transformedNode = cb(etsImportDecl); etsImportDecl != transformedNode) { + etsImportDecl->SetTransformedNode(transformationName, transformedNode); + SetETSImportDeclarations(transformedNode->AsETSImportDeclaration()); } } + EnableHistory(); } void ETSReExportDeclaration::Iterate(const NodeTraverser &cb) const { - etsImportDeclarations_->Iterate(cb); + GetETSImportDeclarations()->Iterate(cb); } void ETSReExportDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ETSReExportDeclaration"}, {"ets_import_declarations", etsImportDeclarations_}}); + dumper->Add({{"type", "ETSReExportDeclaration"}, {"ets_import_declarations", GetETSImportDeclarations()}}); } void ETSReExportDeclaration::Dump([[maybe_unused]] ir::SrcDumper *dumper) const @@ -82,14 +87,16 @@ checker::VerifiedType ETSReExportDeclaration::Check(checker::ETSChecker * /*chec return {this, nullptr}; } -AstNode *ETSReExportDeclaration::Construct(ArenaAllocator *allocator) +ETSReExportDeclaration *ETSReExportDeclaration::Construct(ArenaAllocator *allocator) { - return allocator->New(nullptr, std::vector {}, util::StringView {}, allocator); + std::vector userPaths; + return allocator->New(nullptr, std::move(userPaths), + util::UString(std::string(), allocator).View(), allocator); } void ETSReExportDeclaration::CopyTo(AstNode *other) const { - auto otherImpl = other->AsETSReExportDeclaration(); + auto otherImpl = reinterpret_cast(other); otherImpl->etsImportDeclarations_ = etsImportDeclarations_; otherImpl->userPaths_ = userPaths_; diff --git a/ets2panda/ir/ets/etsReExportDeclaration.h b/ets2panda/ir/ets/etsReExportDeclaration.h index 48d7e6545959250a4ec9fb81a77c536c29ae3c6c..f9ba499b7878dc99ddb9f68cf277cdc5ef8e2479 100644 --- a/ets2panda/ir/ets/etsReExportDeclaration.h +++ b/ets2panda/ir/ets/etsReExportDeclaration.h @@ -31,22 +31,22 @@ public: ETSImportDeclaration *GetETSImportDeclarations() const { - return etsImportDeclarations_; + RETURN_GET(ETSReExportDeclaration, etsImportDeclarations_); } ETSImportDeclaration *GetETSImportDeclarations() { - return etsImportDeclarations_; + RETURN_GET(ETSReExportDeclaration, etsImportDeclarations_); } const ArenaVector &GetUserPaths() const { - return userPaths_; + RETURN_GET(ETSReExportDeclaration, userPaths_); } util::StringView const &GetProgramPath() const { - return programPath_; + RETURN_GET(ETSReExportDeclaration, programPath_); } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -73,8 +73,9 @@ public: } protected: - AstNode *Construct(ArenaAllocator *allocator) override; + ETSReExportDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; + void SetETSImportDeclarations(ETSImportDeclaration *source); private: friend class SizeOfNodeTest; diff --git a/ets2panda/ir/ets/etsStringLiteralType.cpp b/ets2panda/ir/ets/etsStringLiteralType.cpp index d6227f2673e079f710a6e1bb7661a3a91c444be0..178160de40224715787949b5f9dbb6308edd51ea 100644 --- a/ets2panda/ir/ets/etsStringLiteralType.cpp +++ b/ets2panda/ir/ets/etsStringLiteralType.cpp @@ -21,12 +21,7 @@ namespace ark::es2panda::ir { void ETSStringLiteralType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSStringLiteralType::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsStructDeclaration.h b/ets2panda/ir/ets/etsStructDeclaration.h index 538797da5ddeeb66feb5b729162190497580754d..a04c9ab4decdf00eb7294dda8e70853bc5a06f1c 100644 --- a/ets2panda/ir/ets/etsStructDeclaration.h +++ b/ets2panda/ir/ets/etsStructDeclaration.h @@ -30,6 +30,17 @@ public: explicit ETSStructDeclaration(ClassDefinition *const def, ArenaAllocator *const allocator) : ClassDeclaration(AstNodeType::STRUCT_DECLARATION, def, allocator) { + EnableHistory(); + } + + explicit ETSStructDeclaration(ClassDefinition *const def, ArenaAllocator *const allocator, AstNodeHistory *history) + : ClassDeclaration(AstNodeType::STRUCT_DECLARATION, def, allocator) + { + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } void Dump(ir::AstDumper *dumper) const override; @@ -42,6 +53,16 @@ public: { v->Accept(this); } + + ETSStructDeclaration *Construct(ArenaAllocator *allocator) override + { + return allocator->New(nullptr, allocator); + } + + void CopyTo(AstNode *other) const override + { + ClassDeclaration::CopyTo(other); + }; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ets/etsTuple.cpp b/ets2panda/ir/ets/etsTuple.cpp index a9ee2ee9d562cd7153fdb584dd31f2df4b333aa9..c53c9192b70a10797cf8f55a4afe0ce0c7244dca 100644 --- a/ets2panda/ir/ets/etsTuple.cpp +++ b/ets2panda/ir/ets/etsTuple.cpp @@ -29,12 +29,7 @@ void ETSTuple::TransformChildren(const NodeTransformer &cb, std::string_view con } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ETSTuple::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsTypeReference.cpp b/ets2panda/ir/ets/etsTypeReference.cpp index 21db7e18148714de68f28570854a57ebbaef4fcc..ba44804e1424c818f00a4fd7b88404aad1988424 100644 --- a/ets2panda/ir/ets/etsTypeReference.cpp +++ b/ets2panda/ir/ets/etsTypeReference.cpp @@ -21,23 +21,24 @@ #include "compiler/core/pandagen.h" namespace ark::es2panda::ir { + +SETTER_FOR_CHILD(ETSTypeReference, Part, part_, ETSTypeReferencePart *); + void ETSTypeReference::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (auto *transformedNode = cb(part_); part_ != transformedNode) { - part_->SetTransformedNode(transformationName, transformedNode); - part_ = transformedNode->AsETSTypeReferencePart(); - } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } + auto const part = Part(); + if (auto *transformedNode = cb(part); part != transformedNode) { + part->SetTransformedNode(transformationName, transformedNode); + SetPart(transformedNode->AsETSTypeReferencePart()); } + + TransformAnnotations(cb, transformationName); } void ETSTypeReference::Iterate(const NodeTraverser &cb) const { - cb(part_); + auto const part = GetHistoryNodeAs()->part_; + cb(part); for (auto *it : VectorIterationGuard(Annotations())) { cb(it); } @@ -45,7 +46,7 @@ void ETSTypeReference::Iterate(const NodeTraverser &cb) const ir::Identifier *ETSTypeReference::BaseName() const { - ir::ETSTypeReferencePart *partIter = part_; + ir::ETSTypeReferencePart *partIter = Part(); while (partIter->Previous() != nullptr) { partIter = partIter->Previous(); @@ -68,7 +69,7 @@ ir::Identifier *ETSTypeReference::BaseName() const void ETSTypeReference::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ETSTypeReference"}, {"part", part_}, {"annotations", AstDumper::Optional(Annotations())}}); + dumper->Add({{"type", "ETSTypeReference"}, {"part", Part()}, {"annotations", AstDumper::Optional(Annotations())}}); } void ETSTypeReference::Dump(ir::SrcDumper *dumper) const @@ -76,8 +77,8 @@ void ETSTypeReference::Dump(ir::SrcDumper *dumper) const for (auto *anno : Annotations()) { anno->Dump(dumper); } - ES2PANDA_ASSERT(part_ != nullptr); - part_->Dump(dumper); + ES2PANDA_ASSERT(Part() != nullptr); + Part()->Dump(dumper); } void ETSTypeReference::Compile(compiler::PandaGen *pg) const @@ -103,7 +104,7 @@ checker::Type *ETSTypeReference::GetType(checker::ETSChecker *checker) if (TsType() != nullptr) { return TsType(); } - auto *type = part_->GetType(checker); + auto *type = Part()->GetType(checker); if (IsReadonlyType()) { type = checker->GetReadonlyType(type); } @@ -112,14 +113,14 @@ checker::Type *ETSTypeReference::GetType(checker::ETSChecker *checker) ETSTypeReference *ETSTypeReference::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const partClone = part_ != nullptr ? part_->Clone(allocator, nullptr)->AsETSTypeReferencePart() : nullptr; + auto *const partClone = Part() != nullptr ? Part()->Clone(allocator, nullptr)->AsETSTypeReferencePart() : nullptr; auto *const clone = allocator->New(partClone, allocator); if (partClone != nullptr) { partClone->SetParent(clone); } - clone->flags_ = flags_; + clone->flags_ = Modifiers(); if (parent != nullptr) { clone->SetParent(parent); diff --git a/ets2panda/ir/ets/etsTypeReference.h b/ets2panda/ir/ets/etsTypeReference.h index f100af2e5655ac1d19bdb20d12b82830aec8f5c1..9c0676ed238274933ff3ab1e4252e34480ab4d76 100644 --- a/ets2panda/ir/ets/etsTypeReference.h +++ b/ets2panda/ir/ets/etsTypeReference.h @@ -25,16 +25,27 @@ public: explicit ETSTypeReference(ir::ETSTypeReferencePart *part, ArenaAllocator *const allocator) : TypeNode(AstNodeType::ETS_TYPE_REFERENCE, allocator), part_(part) { + EnableHistory(); + } + + explicit ETSTypeReference(ir::ETSTypeReferencePart *part, ArenaAllocator *const allocator, AstNodeHistory *history) + : TypeNode(AstNodeType::ETS_TYPE_REFERENCE, allocator), part_(part) + { + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } ir::ETSTypeReferencePart *Part() { - return part_; + RETURN_GET(ETSTypeReference, part_); } ir::ETSTypeReferencePart *Part() const { - return part_; + RETURN_GET(ETSTypeReference, part_); } ir::Identifier *BaseName() const; @@ -61,6 +72,8 @@ public: private: friend class SizeOfNodeTest; + void SetPart(ETSTypeReferencePart *source); + ir::ETSTypeReferencePart *part_; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ets/etsTypeReferencePart.cpp b/ets2panda/ir/ets/etsTypeReferencePart.cpp index e0686ef0761195da0a48797619b9dd6ca3cdca43..88af17dba92391cae2606f267dbb758221c52fb3 100644 --- a/ets2panda/ir/ets/etsTypeReferencePart.cpp +++ b/ets2panda/ir/ets/etsTypeReferencePart.cpp @@ -22,55 +22,68 @@ #include "compiler/core/pandagen.h" namespace ark::es2panda::ir { + +SETTER_FOR_CHILD(ETSTypeReferencePart, Name, name_, Expression *); +SETTER_FOR_CHILD(ETSTypeReferencePart, TypeParams, typeParams_, TSTypeParameterInstantiation *); +SETTER_FOR_CHILD(ETSTypeReferencePart, Previous, prev_, ETSTypeReferencePart *); + void ETSTypeReferencePart::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - if (auto *transformedNode = cb(name_); name_ != transformedNode) { - name_->SetTransformedNode(transformationName, transformedNode); - name_ = transformedNode->AsExpression(); + auto const name = Name(); + if (name != nullptr) { + if (auto *transformedNode = cb(name); name != transformedNode) { + name->SetTransformedNode(transformationName, transformedNode); + SetName(transformedNode->AsExpression()); + } } - if (typeParams_ != nullptr) { - if (auto *transformedNode = cb(typeParams_); typeParams_ != transformedNode) { - typeParams_->SetTransformedNode(transformationName, transformedNode); - typeParams_ = transformedNode->AsTSTypeParameterInstantiation(); + auto const typeParams = TypeParams(); + if (typeParams != nullptr) { + if (auto *transformedNode = cb(typeParams); typeParams != transformedNode) { + typeParams->SetTransformedNode(transformationName, transformedNode); + SetTypeParams(transformedNode->AsTSTypeParameterInstantiation()); } } - if (prev_ != nullptr) { - if (auto *transformedNode = cb(prev_); prev_ != transformedNode) { - prev_->SetTransformedNode(transformationName, transformedNode); - prev_ = transformedNode->AsETSTypeReferencePart(); + auto const prev = Previous(); + if (prev != nullptr) { + if (auto *transformedNode = cb(prev); prev != transformedNode) { + prev->SetTransformedNode(transformationName, transformedNode); + SetPrevious(transformedNode->AsETSTypeReferencePart()); } } } void ETSTypeReferencePart::Iterate(const NodeTraverser &cb) const { - cb(name_); + auto const name = GetHistoryNodeAs()->name_; + cb(name); - if (typeParams_ != nullptr) { - cb(typeParams_); + auto const typeParams = GetHistoryNodeAs()->typeParams_; + if (typeParams != nullptr) { + cb(typeParams); } - if (prev_ != nullptr) { - cb(prev_); + auto const prev = GetHistoryNodeAs()->prev_; + if (prev != nullptr) { + cb(prev); } } void ETSTypeReferencePart::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "ETSTypeReferencePart"}, - {"name", name_}, - {"typeParams", AstDumper::Optional(typeParams_)}, - {"previous", AstDumper::Optional(prev_)}}); + {"name", Name()}, + {"typeParams", AstDumper::Optional(TypeParams())}, + {"previous", AstDumper::Optional(Previous())}}); } void ETSTypeReferencePart::Dump(ir::SrcDumper *dumper) const { - ES2PANDA_ASSERT(name_ != nullptr); - name_->Dump(dumper); - if (typeParams_ != nullptr) { - typeParams_->Dump(dumper); + ES2PANDA_ASSERT(Name() != nullptr); + Name()->Dump(dumper); + if (TypeParams() != nullptr) { + TypeParams()->Dump(dumper); } } @@ -95,24 +108,25 @@ checker::VerifiedType ETSTypeReferencePart::Check(checker::ETSChecker *checker) checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *const checker) { - ES2PANDA_ASSERT(name_->IsIdentifier() || name_->IsTSQualifiedName()); + auto const name = Name(); + ES2PANDA_ASSERT(name->IsIdentifier() || name->IsTSQualifiedName()); Identifier *ident = GetIdent(); varbinder::Variable *variable = nullptr; - if (name_->IsIdentifier()) { + if (name->IsIdentifier()) { variable = ident->Variable(); } else { - if (name_->AsTSQualifiedName()->Left()->Variable() != nullptr && - name_->AsTSQualifiedName()->Left()->Variable()->TsType() != nullptr && - name_->AsTSQualifiedName()->Left()->Variable()->TsType()->IsETSObjectType()) { - variable = name_->AsTSQualifiedName()->Left()->Variable()->TsType()->AsETSObjectType()->GetProperty( + if (name->AsTSQualifiedName()->Left()->Variable() != nullptr && + name->AsTSQualifiedName()->Left()->Variable()->TsType() != nullptr && + name->AsTSQualifiedName()->Left()->Variable()->TsType()->IsETSObjectType()) { + variable = name->AsTSQualifiedName()->Left()->Variable()->TsType()->AsETSObjectType()->GetProperty( ident->Name(), checker::PropertySearchFlags::SEARCH_DECL); } } if (variable != nullptr && variable->Declaration()->IsTypeAliasDecl()) { - return checker->HandleTypeAlias(name_, typeParams_, + return checker->HandleTypeAlias(name, TypeParams(), variable->Declaration()->AsTypeAliasDecl()->Node()->AsTSTypeAliasDeclaration()); } @@ -130,7 +144,7 @@ checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *co if (ident->Name() == compiler::Signatures::READONLY_TYPE_NAME || ident->Name() == compiler::Signatures::REQUIRED_TYPE_NAME) { - return checker->HandleUtilityTypeParameterNode(typeParams_, ident); + return checker->HandleUtilityTypeParameterNode(TypeParams(), ident); } if (ident->Name() == compiler::Signatures::PARTIAL_TYPE_NAME) { @@ -150,11 +164,12 @@ checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *co checker::Type *ETSTypeReferencePart::HandleFixedArrayType(checker::ETSChecker *const checker) { - if (typeParams_ == nullptr || typeParams_->Params().size() != 1) { + auto const typeParams = TypeParams(); + if (typeParams == nullptr || typeParams->Params().size() != 1) { checker->LogError(diagnostic::FIXED_ARRAY_PARAM_ERROR, {}, Start()); return checker->GlobalTypeError(); } - checker::Type *type = checker->CreateETSArrayType(typeParams_->Params()[0]->GetType(checker), IsReadonlyType()); + checker::Type *type = checker->CreateETSArrayType(typeParams->Params()[0]->GetType(checker), IsReadonlyType()); SetTsType(type); return type; } @@ -162,14 +177,15 @@ checker::Type *ETSTypeReferencePart::HandleFixedArrayType(checker::ETSChecker *c checker::Type *ETSTypeReferencePart::HandlePartialType(checker::ETSChecker *const checker, const Identifier *const ident) { - auto *baseType = checker->HandleUtilityTypeParameterNode(typeParams_, ident); + auto const typeParams = TypeParams(); + auto *baseType = checker->HandleUtilityTypeParameterNode(typeParams, ident); if (baseType != nullptr && baseType->IsETSObjectType() && !baseType->AsETSObjectType()->TypeArguments().empty()) { // we treat Partial> class as a different copy from A now, // but not a generic type param for Partial<> - if (typeParams_ != nullptr) { - for (auto &typeRef : typeParams_->Params()) { + if (typeParams != nullptr) { + for (auto &typeRef : typeParams->Params()) { checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(), - typeRef->AsETSTypeReference()->Part()->typeParams_, Start()); + typeRef->AsETSTypeReference()->Part()->TypeParams(), Start()); baseType = ctx.Result(); } } @@ -187,35 +203,37 @@ checker::Type *ETSTypeReferencePart::GetType(checker::ETSChecker *checker) } } } - if (prev_ == nullptr) { - if (name_->IsIdentifier() || name_->IsTSQualifiedName()) { + auto const name = Name(); + if (Previous() == nullptr) { + if (name->IsIdentifier() || name->IsTSQualifiedName()) { SetTsType(HandleInternalTypes(checker)); } if (TsType() == nullptr) { - checker::Type *baseType = checker->GetReferencedTypeBase(name_); + checker::Type *baseType = checker->GetReferencedTypeBase(name); ES2PANDA_ASSERT(baseType != nullptr); if (baseType->IsETSObjectType()) { - checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(), typeParams_, Start()); + checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(), TypeParams(), Start()); SetTsType(ctx.Result()); } else { SetTsType(baseType); } } } else { - checker::Type *baseType = prev_->GetType(checker); - SetTsType(checker->GetReferencedTypeFromBase(baseType, name_)); + checker::Type *baseType = Previous()->GetType(checker); + SetTsType(checker->GetReferencedTypeFromBase(baseType, name)); } return TsType(); } ETSTypeReferencePart *ETSTypeReferencePart::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - auto *const nameClone = name_ != nullptr ? name_->Clone(allocator, nullptr)->AsExpression() : nullptr; + auto *const nameClone = Name() != nullptr ? Name()->Clone(allocator, nullptr)->AsExpression() : nullptr; auto *const typeParamsClone = - typeParams_ != nullptr ? typeParams_->Clone(allocator, nullptr)->AsTSTypeParameterInstantiation() : nullptr; - auto *const prevClone = prev_ != nullptr ? prev_->Clone(allocator, nullptr)->AsETSTypeReferencePart() : nullptr; + TypeParams() != nullptr ? TypeParams()->Clone(allocator, nullptr)->AsTSTypeParameterInstantiation() : nullptr; + auto *const prevClone = + Previous() != nullptr ? Previous()->Clone(allocator, nullptr)->AsETSTypeReferencePart() : nullptr; auto *const clone = allocator->New(nameClone, typeParamsClone, prevClone, allocator); if (nameClone != nullptr) { @@ -240,12 +258,13 @@ ETSTypeReferencePart *ETSTypeReferencePart::Clone(ArenaAllocator *const allocato ir::Identifier *ETSTypeReferencePart::GetIdent() { - if (name_->IsTSQualifiedName()) { - auto ident = name_->AsTSQualifiedName()->Right(); + auto const name = Name(); + if (name->IsTSQualifiedName()) { + auto ident = name->AsTSQualifiedName()->Right(); ES2PANDA_ASSERT(ident->IsIdentifier()); return ident->AsIdentifier(); } - return name_->AsIdentifier(); + return name->AsIdentifier(); } ETSTypeReferencePart *ETSTypeReferencePart::Construct(ArenaAllocator *allocator) diff --git a/ets2panda/ir/ets/etsTypeReferencePart.h b/ets2panda/ir/ets/etsTypeReferencePart.h index 4b1e6aba373dae5440ecf75c7f3606d47b884a2e..679fbe41376f4aeb33735106ffd0d39be9d83dc4 100644 --- a/ets2panda/ir/ets/etsTypeReferencePart.h +++ b/ets2panda/ir/ets/etsTypeReferencePart.h @@ -26,36 +26,65 @@ public: ir::ETSTypeReferencePart *prev, ArenaAllocator *const allocator) : TypeNode(AstNodeType::ETS_TYPE_REFERENCE_PART, allocator), name_(name), typeParams_(typeParams), prev_(prev) { + EnableHistory(); } explicit ETSTypeReferencePart(ir::Expression *name, ArenaAllocator *const allocator) : TypeNode(AstNodeType::ETS_TYPE_REFERENCE_PART, allocator), name_(name) { + EnableHistory(); + } + + explicit ETSTypeReferencePart(ir::Expression *name, ArenaAllocator *const allocator, AstNodeHistory *history) + : TypeNode(AstNodeType::ETS_TYPE_REFERENCE_PART, allocator), name_(name) + { + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } + } + + explicit ETSTypeReferencePart(ir::Expression *name, ir::TSTypeParameterInstantiation *typeParams, + ir::ETSTypeReferencePart *prev, ArenaAllocator *const allocator, + AstNodeHistory *history) + : TypeNode(AstNodeType::ETS_TYPE_REFERENCE_PART, allocator), name_(name), typeParams_(typeParams), prev_(prev) + { + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } ir::ETSTypeReferencePart *Previous() { - return prev_; + RETURN_GET(ETSTypeReferencePart, prev_); } const ir::ETSTypeReferencePart *Previous() const { - return prev_; + RETURN_GET(ETSTypeReferencePart, prev_); } ir::Expression *Name() { - return name_; + RETURN_GET(ETSTypeReferencePart, name_); } ir::TSTypeParameterInstantiation *TypeParams() { - return typeParams_; + RETURN_GET(ETSTypeReferencePart, typeParams_); + } + + const ir::TSTypeParameterInstantiation *TypeParams() const + { + RETURN_GET(ETSTypeReferencePart, typeParams_); } const ir::Expression *Name() const { - return name_; + RETURN_GET(ETSTypeReferencePart, name_); } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -85,6 +114,10 @@ private: checker::Type *HandleFixedArrayType(checker::ETSChecker *const checker); friend class SizeOfNodeTest; + void SetName(ir::Expression *source); + void SetTypeParams(ir::TSTypeParameterInstantiation *source); + void SetPrevious(ir::ETSTypeReferencePart *source); + ir::Expression *name_; ir::TSTypeParameterInstantiation *typeParams_ {}; ir::ETSTypeReferencePart *prev_ {}; diff --git a/ets2panda/ir/ets/etsUnionType.cpp b/ets2panda/ir/ets/etsUnionType.cpp index 39860832e491e56ec059c3e1f62a180d340bbe25..a64059e95a83a8db7c63598516d5487e2d3ba581 100644 --- a/ets2panda/ir/ets/etsUnionType.cpp +++ b/ets2panda/ir/ets/etsUnionType.cpp @@ -26,12 +26,8 @@ void ETSUnionType::TransformChildren(const NodeTransformer &cb, std::string_view it = static_cast(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void ETSUnionType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ets/etsWildcardType.cpp b/ets2panda/ir/ets/etsWildcardType.cpp index 24000a8aa5cfe80c17b98e6c9ec38241fea006d1..ab5ffc9e50fbb072feb58b2639252def5c8c2610 100644 --- a/ets2panda/ir/ets/etsWildcardType.cpp +++ b/ets2panda/ir/ets/etsWildcardType.cpp @@ -32,12 +32,8 @@ void ETSWildcardType::TransformChildren(const NodeTransformer &cb, std::string_v typeReference_ = transformedNode->AsETSTypeReference(); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void ETSWildcardType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/expression.h b/ets2panda/ir/expression.h index 52b74a8329b414f344db2dc132fd21f69b1eca28..00c10eaec81bcce401519dc9cef807033c92f126 100644 --- a/ets2panda/ir/expression.h +++ b/ets2panda/ir/expression.h @@ -33,24 +33,26 @@ public: [[nodiscard]] bool IsGrouped() const noexcept { - return grouped_; + return AstNode::GetHistoryNodeAs()->grouped_; } void SetGrouped() noexcept { - grouped_ = true; + if (!IsGrouped()) { + AstNode::GetOrCreateHistoryNodeAs()->grouped_ = true; + } } [[nodiscard]] const Literal *AsLiteral() const { ES2PANDA_ASSERT(IsLiteral()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } [[nodiscard]] Literal *AsLiteral() { ES2PANDA_ASSERT(IsLiteral()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } [[nodiscard]] virtual bool IsLiteral() const noexcept @@ -76,25 +78,25 @@ public: [[nodiscard]] TypeNode *AsTypeNode() { ES2PANDA_ASSERT(IsTypeNode()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } [[nodiscard]] const TypeNode *AsTypeNode() const { ES2PANDA_ASSERT(IsTypeNode()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } [[nodiscard]] AnnotatedExpression *AsAnnotatedExpression() { ES2PANDA_ASSERT(IsAnnotatedExpression()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } [[nodiscard]] const AnnotatedExpression *AsAnnotatedExpression() const { ES2PANDA_ASSERT(IsAnnotatedExpression()); - return reinterpret_cast(this); + return reinterpret_cast(GetHistoryNodeAs()); } bool IsBrokenExpression() const noexcept; @@ -109,7 +111,7 @@ protected: Expression(Expression const &other) : TypedAstNode(static_cast(other)) { - grouped_ = other.grouped_; + grouped_ = other.IsGrouped(); } private: @@ -150,12 +152,12 @@ public: [[nodiscard]] bool IsOptional() const noexcept { - return optional_; + return GetHistoryNodeAs()->optional_; } void ClearOptional() noexcept { - optional_ = false; + GetOrCreateHistoryNodeAs()->optional_ = false; } protected: diff --git a/ets2panda/ir/expressions/arrayExpression.h b/ets2panda/ir/expressions/arrayExpression.h index 2cc1924a89d1f3e1f2942f7d56d4aaf973c3a724..2af3767f2b671de1b0f2120afad0a66256e950b0 100644 --- a/ets2panda/ir/expressions/arrayExpression.h +++ b/ets2panda/ir/expressions/arrayExpression.h @@ -119,11 +119,6 @@ public: return decorators_; } - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); - } - void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/expressions/arrowFunctionExpression.cpp b/ets2panda/ir/expressions/arrowFunctionExpression.cpp index c4941954ec3ff972584c78b318450cca6746c6d6..772cf69fc00187f97ae507b676a4bf3f41238c4e 100644 --- a/ets2panda/ir/expressions/arrowFunctionExpression.cpp +++ b/ets2panda/ir/expressions/arrowFunctionExpression.cpp @@ -28,12 +28,7 @@ void ArrowFunctionExpression::TransformChildren(const NodeTransformer &cb, std:: func_ = transformedNode->AsScriptFunction(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void ArrowFunctionExpression::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/expressions/functionExpression.cpp b/ets2panda/ir/expressions/functionExpression.cpp index 8e39aaff4b939adf8686cdbb9cde559be716d632..4b01e0597d81f9957ea456a0de30301719fd53f2 100644 --- a/ets2panda/ir/expressions/functionExpression.cpp +++ b/ets2panda/ir/expressions/functionExpression.cpp @@ -89,4 +89,5 @@ void FunctionExpression::CopyTo(AstNode *other) const Expression::CopyTo(other); } + } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/expressions/identifier.cpp b/ets2panda/ir/expressions/identifier.cpp index 716cc86102ab6583d779628d154721442228210f..ee26d04b95e93c6d660393260075ebcd68a9304b 100644 --- a/ets2panda/ir/expressions/identifier.cpp +++ b/ets2panda/ir/expressions/identifier.cpp @@ -30,11 +30,13 @@ Identifier::Identifier([[maybe_unused]] Tag const tag, Identifier const &other, for (auto *decorator : other.decorators_) { decorators_.emplace_back(decorator->Clone(allocator, this)); } + EnableHistory(); } Identifier::Identifier(ArenaAllocator *const allocator) : Identifier(ERROR_LITERAL, allocator) { flags_ |= IdentifierFlags::ERROR_PLACEHOLDER; + EnableHistory(); } Identifier::Identifier(util::StringView const name, ArenaAllocator *const allocator) @@ -43,6 +45,7 @@ Identifier::Identifier(util::StringView const name, ArenaAllocator *const alloca if (name == ERROR_LITERAL) { flags_ |= IdentifierFlags::ERROR_PLACEHOLDER; } + EnableHistory(); } Identifier::Identifier(util::StringView const name, TypeNode *const typeAnnotation, ArenaAllocator *const allocator) @@ -51,12 +54,13 @@ Identifier::Identifier(util::StringView const name, TypeNode *const typeAnnotati if (name == ERROR_LITERAL) { flags_ |= IdentifierFlags::ERROR_PLACEHOLDER; } + EnableHistory(); } void Identifier::SetName(const util::StringView &newName) noexcept { ES2PANDA_ASSERT(newName != ERROR_LITERAL); - name_ = newName; + GetOrCreateHistoryNodeAs()->name_ = newName; } Identifier *Identifier::Clone(ArenaAllocator *const allocator, AstNode *const parent) @@ -72,6 +76,13 @@ Identifier *Identifier::Clone(ArenaAllocator *const allocator, AstNode *const pa return clone; } +void Identifier::SetValueDecorators(Decorator *source, size_t index) +{ + auto newNode = this->GetOrCreateHistoryNodeAs(); + auto &arenaVector = newNode->decorators_; + arenaVector[index] = source; +} + Identifier *Identifier::CloneReference(ArenaAllocator *const allocator, AstNode *const parent) { auto *const clone = Clone(allocator, parent); @@ -90,10 +101,11 @@ void Identifier::TransformChildren(const NodeTransformer &cb, std::string_view c } } - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } } @@ -104,14 +116,14 @@ void Identifier::Iterate(const NodeTraverser &cb) const cb(TypeAnnotation()); } - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } } ValidationInfo Identifier::ValidateExpression() { - if ((flags_ & IdentifierFlags::OPTIONAL) != 0U) { + if ((IdFlags() & IdentifierFlags::OPTIONAL) != 0U) { return {"Unexpected token '?'.", Start()}; } @@ -126,10 +138,10 @@ ValidationInfo Identifier::ValidateExpression() void Identifier::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", IsPrivateIdent() ? "PrivateIdentifier" : "Identifier"}, - {"name", name_}, + {"name", Name()}, {"typeAnnotation", AstDumper::Optional(TypeAnnotation())}, {"optional", AstDumper::Optional(IsOptional())}, - {"decorators", decorators_}}); + {"decorators", Decorators()}}); } void Identifier::Dump(ir::SrcDumper *dumper) const @@ -143,7 +155,7 @@ void Identifier::Dump(ir::SrcDumper *dumper) const dumper->Add("private "); } - auto name = std::string(name_); + auto name = std::string(Name()); std::string propertyStr = compiler::Signatures::PROPERTY.data(); if (UNLIKELY(name.find(propertyStr) != std::string::npos)) { name.replace(name.find(propertyStr), propertyStr.length(), "_$property$_"); diff --git a/ets2panda/ir/expressions/identifier.h b/ets2panda/ir/expressions/identifier.h index da71df56cc59688f33d64751c131a4c1bbbc72f2..855efad6a999d5a76ad694855761498ed6b07287 100644 --- a/ets2panda/ir/expressions/identifier.h +++ b/ets2panda/ir/expressions/identifier.h @@ -68,42 +68,39 @@ public: [[nodiscard]] const util::StringView &Name() const noexcept { - return name_; + RETURN_GET(Identifier, name_); } [[nodiscard]] util::StringView &Name() noexcept { - return name_; + return GetHistoryNodeAs()->name_; } void SetName(const util::StringView &newName) noexcept; - [[nodiscard]] const ArenaVector &Decorators() const noexcept - { - return decorators_; - } + void SetValueDecorators(Decorator *source, size_t index); - const ArenaVector *DecoratorsPtr() const override + [[nodiscard]] const ArenaVector &Decorators() const noexcept { - return &Decorators(); + return GetHistoryNodeAs()->decorators_; } bool IsErrorPlaceHolder() const noexcept { - return (flags_ & IdentifierFlags::ERROR_PLACEHOLDER) != 0; + return (IdFlags() & IdentifierFlags::ERROR_PLACEHOLDER) != 0; } [[nodiscard]] bool IsOptional() const noexcept { - return (flags_ & IdentifierFlags::OPTIONAL) != 0; + return (IdFlags() & IdentifierFlags::OPTIONAL) != 0; } void SetOptional(bool const optional) noexcept { if (optional) { - flags_ |= IdentifierFlags::OPTIONAL; + AddIdFlags(IdentifierFlags::OPTIONAL); } else { - flags_ &= ~IdentifierFlags::OPTIONAL; + ClearIdFlags(IdentifierFlags::OPTIONAL); } } @@ -114,86 +111,86 @@ public: [[nodiscard]] bool IsTdz() const noexcept { - return (flags_ & IdentifierFlags::TDZ) != 0; + return (IdFlags() & IdentifierFlags::TDZ) != 0; } void SetTdz() noexcept { - flags_ |= IdentifierFlags::TDZ; + AddIdFlags(IdentifierFlags::TDZ); } void SetAccessor() noexcept { - flags_ |= IdentifierFlags::GET; + AddIdFlags(IdentifierFlags::GET); } [[nodiscard]] bool IsAccessor() const noexcept { - return (flags_ & IdentifierFlags::GET) != 0; + return (IdFlags() & IdentifierFlags::GET) != 0; } void SetMutator() noexcept { - flags_ |= IdentifierFlags::SET; + AddIdFlags(IdentifierFlags::SET); } [[nodiscard]] bool IsMutator() const noexcept { - return (flags_ & IdentifierFlags::SET) != 0; + return (IdFlags() & IdentifierFlags::SET) != 0; } [[nodiscard]] bool IsReceiver() const noexcept { - return name_ == varbinder::VarBinder::MANDATORY_PARAM_THIS; + return Name() == varbinder::VarBinder::MANDATORY_PARAM_THIS; } [[nodiscard]] bool IsPrivateIdent() const noexcept { - return (flags_ & IdentifierFlags::PRIVATE) != 0; + return (IdFlags() & IdentifierFlags::PRIVATE) != 0; } void SetPrivate(bool const isPrivate) noexcept { if (isPrivate) { - flags_ |= IdentifierFlags::PRIVATE; + AddIdFlags(IdentifierFlags::PRIVATE); } else { - flags_ &= ~IdentifierFlags::PRIVATE; + ClearIdFlags(IdentifierFlags::PRIVATE); } } [[nodiscard]] bool IsIgnoreBox() const noexcept { - return (flags_ & IdentifierFlags::IGNORE_BOX) != 0; + return (IdFlags() & IdentifierFlags::IGNORE_BOX) != 0; } void SetIgnoreBox() noexcept { - flags_ |= IdentifierFlags::IGNORE_BOX; + AddIdFlags(IdentifierFlags::IGNORE_BOX); } [[nodiscard]] bool IsAnnotationDecl() const noexcept { - return (flags_ & IdentifierFlags::ANNOTATIONDECL) != 0; + return (IdFlags() & IdentifierFlags::ANNOTATIONDECL) != 0; } void SetAnnotationDecl() noexcept { - flags_ |= IdentifierFlags::ANNOTATIONDECL; + AddIdFlags(IdentifierFlags::ANNOTATIONDECL); } [[nodiscard]] bool IsAnnotationUsage() const noexcept { - return (flags_ & IdentifierFlags::ANNOTATIONUSAGE) != 0; + return (IdFlags() & IdentifierFlags::ANNOTATIONUSAGE) != 0; } void SetAnnotationUsage() noexcept { - flags_ |= IdentifierFlags::ANNOTATIONUSAGE; + AddIdFlags(IdentifierFlags::ANNOTATIONUSAGE); } void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + GetOrCreateHistoryNodeAs()->decorators_ = std::move(decorators); } [[nodiscard]] Identifier *Clone(ArenaAllocator *allocator, AstNode *parent) override; @@ -222,7 +219,42 @@ public: v->Accept(this); } + Identifier *Construct(ArenaAllocator *allocator) override + { + return allocator->New(allocator); + } + + void CopyTo(AstNode *other) const override + { + auto otherImpl = other->AsIdentifier(); + + otherImpl->name_ = name_; + otherImpl->flags_ = flags_; + otherImpl->decorators_ = decorators_; + + AnnotatedExpression::CopyTo(other); + }; + private: + IdentifierFlags IdFlags() const + { + return GetHistoryNodeAs()->flags_; + } + + void AddIdFlags(IdentifierFlags const flags) noexcept + { + if (!All(IdFlags(), flags)) { + GetOrCreateHistoryNodeAs()->flags_ |= flags; + } + } + + void ClearIdFlags(IdentifierFlags const flags) noexcept + { + if (Any(IdFlags(), flags)) { + GetOrCreateHistoryNodeAs()->flags_ &= ~flags; + } + } + bool CheckDeclarationsPart2(const ir::AstNode *parent, ScriptExtension ext) const; bool CheckDeclarationsPart1(const ir::AstNode *parent, ScriptExtension ext) const; bool CheckNotDeclarations(const ir::AstNode *parent, ScriptExtension ext) const; diff --git a/ets2panda/ir/expressions/objectExpression.h b/ets2panda/ir/expressions/objectExpression.h index 7f7e05007f1ef58cdd781ba656d23cdf10619137..45e893cb515170ad7befecf6ad37816a4b32c72f 100644 --- a/ets2panda/ir/expressions/objectExpression.h +++ b/ets2panda/ir/expressions/objectExpression.h @@ -81,11 +81,6 @@ public: return decorators_; } - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); - } - void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/module/importDeclaration.cpp b/ets2panda/ir/module/importDeclaration.cpp index d48246d887744c5e2ce67873d1355c6fe2751dfa..ee33083d7825da99a83c44e822dd4d5c680d8d5b 100644 --- a/ets2panda/ir/module/importDeclaration.cpp +++ b/ets2panda/ir/module/importDeclaration.cpp @@ -24,46 +24,54 @@ namespace ark::es2panda::ir { +SETTER_FOR_CHILD(ImportDeclaration, Source, source_, StringLiteral *); + +SETTER_FOR_ARENAVECTOR_CHILD(ImportDeclaration, Specifiers, specifiers_, AstNode *); + void ImportDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - if (auto *transformedNode = cb(source_); source_ != transformedNode) { - source_->SetTransformedNode(transformationName, transformedNode); - source_ = transformedNode->AsStringLiteral(); + auto const source = Source(); + if (auto *transformedNode = cb(source); source != transformedNode) { + source->SetTransformedNode(transformationName, transformedNode); + SetSource(transformedNode->AsStringLiteral()); } - for (auto *&it : VectorIterationGuard(specifiers_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode; + auto const &specifiers = Specifiers(); + for (size_t index = 0; index < specifiers.size(); ++index) { + if (auto *transformedNode = cb(specifiers[index]); specifiers[index] != transformedNode) { + specifiers[index]->SetTransformedNode(transformationName, transformedNode); + SetValueSpecifiers(transformedNode, index); } } } void ImportDeclaration::Iterate(const NodeTraverser &cb) const { - cb(source_); + auto source = GetHistoryNodeAs()->source_; + cb(source); - for (auto *it : VectorIterationGuard(specifiers_)) { + for (auto *it : VectorIterationGuard(Specifiers())) { cb(it); } } void ImportDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ImportDeclaration"}, {"source", source_}, {"specifiers", specifiers_}}); + dumper->Add({{"type", "ImportDeclaration"}, {"source", Source()}, {"specifiers", Specifiers()}}); } void ImportDeclaration::Dump(ir::SrcDumper *dumper) const { dumper->Add("import "); - if (specifiers_.size() == 1 && - (specifiers_[0]->IsImportNamespaceSpecifier() || specifiers_[0]->IsImportDefaultSpecifier())) { - specifiers_[0]->Dump(dumper); + auto const &specifiers = Specifiers(); + if (specifiers.size() == 1 && + (specifiers[0]->IsImportNamespaceSpecifier() || specifiers[0]->IsImportDefaultSpecifier())) { + specifiers[0]->Dump(dumper); } else { dumper->Add("{ "); - for (auto specifier : specifiers_) { + for (auto specifier : specifiers) { specifier->Dump(dumper); - if (specifier != specifiers_.back()) { + if (specifier != specifiers.back()) { dumper->Add(", "); } } @@ -71,7 +79,7 @@ void ImportDeclaration::Dump(ir::SrcDumper *dumper) const } dumper->Add(" from "); - source_->Dump(dumper); + Source()->Dump(dumper); dumper->Add(";"); dumper->Endl(); } @@ -104,7 +112,7 @@ ImportDeclaration *ImportDeclaration::Construct(ArenaAllocator *allocator) void ImportDeclaration::CopyTo(AstNode *other) const { - auto otherImpl = other->AsImportDeclaration(); + auto otherImpl = static_cast(other); otherImpl->source_ = source_; otherImpl->specifiers_ = specifiers_; diff --git a/ets2panda/ir/module/importDeclaration.h b/ets2panda/ir/module/importDeclaration.h index c3f28438e23e5974a13d25d6c32d456e7071926c..73edf8ced3875e09874536c104b24a2db163c831 100644 --- a/ets2panda/ir/module/importDeclaration.h +++ b/ets2panda/ir/module/importDeclaration.h @@ -25,6 +25,11 @@ enum class ImportKinds { ALL, TYPES }; class ImportDeclaration : public Statement { public: + void EmplaceSpecifiers(AstNode *source); + void ClearSpecifiers(); + void SetValueSpecifiers(AstNode *source, size_t index); + ArenaVector &Specifiers(); + explicit ImportDeclaration(StringLiteral *source, ArenaVector &&specifiers, const ImportKinds importKinds = ImportKinds::ALL) : Statement(AstNodeType::IMPORT_DECLARATION), @@ -32,26 +37,36 @@ public: specifiers_(std::move(specifiers)), importKinds_(importKinds) { + EnableHistory(); } - const StringLiteral *Source() const + explicit ImportDeclaration(StringLiteral *source, ArenaVector &&specifiers, + const ImportKinds importKinds, AstNodeHistory *history) + : Statement(AstNodeType::IMPORT_DECLARATION), + source_(source), + specifiers_(std::move(specifiers)), + importKinds_(importKinds) { - return source_; + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } - StringLiteral *Source() + const StringLiteral *Source() const { - return source_; + RETURN_GET(ImportDeclaration, source_); } - const ArenaVector &Specifiers() const + StringLiteral *Source() { - return specifiers_; + RETURN_GET(ImportDeclaration, source_); } - ArenaVector &Specifiers() + const ArenaVector &Specifiers() const { - return specifiers_; + RETURN_GET(ImportDeclaration, specifiers_); } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -70,7 +85,7 @@ public: bool IsTypeKind() const { - return importKinds_ == ImportKinds::TYPES; + return GetHistoryNodeAs()->importKinds_ == ImportKinds::TYPES; } ImportDeclaration *Construct(ArenaAllocator *allocator) override; @@ -78,6 +93,8 @@ public: private: friend class SizeOfNodeTest; + void SetSource(StringLiteral *source); + StringLiteral *source_; ArenaVector specifiers_; ImportKinds importKinds_; diff --git a/ets2panda/ir/opaqueTypeNode.cpp b/ets2panda/ir/opaqueTypeNode.cpp index b76b69d868e74c6418b81d26a740307372a81de5..4a74b389756ec682bc543df34f615d8380870601 100644 --- a/ets2panda/ir/opaqueTypeNode.cpp +++ b/ets2panda/ir/opaqueTypeNode.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void OpaqueTypeNode::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void OpaqueTypeNode::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/statements/annotationDeclaration.cpp b/ets2panda/ir/statements/annotationDeclaration.cpp index aab66f2db2756339dd3b5047e4d98a6ed5c8ce1c..3b7a13f106c744037dc00a513b2e66a199b37c72 100644 --- a/ets2panda/ir/statements/annotationDeclaration.cpp +++ b/ets2panda/ir/statements/annotationDeclaration.cpp @@ -21,36 +21,40 @@ #include "ir/srcDump.h" namespace ark::es2panda::ir { + +SETTER_FOR_FIELD(AnnotationDeclaration, InternalName, internalName_, util::StringView); + +SETTER_FOR_CHILD(AnnotationDeclaration, Expr, expr_, Expression *); + +SETTER_FOR_ARENAVECTOR_CHILD(AnnotationDeclaration, Properties, properties_, AstNode *); + void AnnotationDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(properties_)) { + for (auto *&it : VectorIterationGuard(Properties())) { if (auto *transformedNode = cb(it); it != transformedNode) { it->SetTransformedNode(transformationName, transformedNode); it = transformedNode; } } - if (expr_ != nullptr) { - if (auto *transformedNode = cb(expr_); expr_ != transformedNode) { - expr_->SetTransformedNode(transformationName, transformedNode); - expr_ = transformedNode->AsIdentifier(); + auto const expr = Expr(); + if (expr != nullptr) { + if (auto *transformedNode = cb(expr); expr != transformedNode) { + expr->SetTransformedNode(transformationName, transformedNode); + SetExpr(transformedNode->AsIdentifier()); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void AnnotationDeclaration::Iterate(const NodeTraverser &cb) const { - if (expr_ != nullptr) { - cb(expr_); + auto const expr = GetHistoryNodeAs()->expr_; + if (expr != nullptr) { + cb(expr); } - for (auto *it : VectorIterationGuard(properties_)) { + for (auto *it : VectorIterationGuard(Properties())) { cb(it); } @@ -61,24 +65,25 @@ void AnnotationDeclaration::Iterate(const NodeTraverser &cb) const void AnnotationDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"Expr", expr_}, {"properties", properties_}, {"annotations", AstDumper::Optional(Annotations())}}); + dumper->Add({{"Expr", Expr()}, {"properties", Properties()}, {"annotations", AstDumper::Optional(Annotations())}}); } void AnnotationDeclaration::Dump(ir::SrcDumper *dumper) const { // re-understand for (auto *anno : Annotations()) { anno->Dump(dumper); } - ES2PANDA_ASSERT(expr_ != nullptr); + ES2PANDA_ASSERT(Expr() != nullptr); dumper->Add("@interface "); - expr_->Dump(dumper); + Expr()->Dump(dumper); dumper->Add(" {"); - if (!properties_.empty()) { + auto const properties = Properties(); + if (!properties.empty()) { dumper->IncrIndent(); dumper->Endl(); - for (auto elem : properties_) { + for (auto elem : properties) { elem->Dump(dumper); - if (elem == properties_.back()) { + if (elem == properties.back()) { dumper->DecrIndent(); } } @@ -108,14 +113,13 @@ checker::VerifiedType AnnotationDeclaration::Check(checker::ETSChecker *checker) Identifier *AnnotationDeclaration::GetBaseName() const { - if (expr_->IsIdentifier()) { - return expr_->AsIdentifier(); + if (Expr()->IsIdentifier()) { + return GetHistoryNodeAs()->expr_->AsIdentifier(); } - auto *part = expr_->AsETSTypeReference()->Part(); + auto *part = Expr()->AsETSTypeReference()->Part(); return part->Name()->AsTSQualifiedName()->Right(); } - -AstNode *AnnotationDeclaration::Construct(ArenaAllocator *allocator) +AnnotationDeclaration *AnnotationDeclaration::Construct(ArenaAllocator *allocator) { return allocator->New(nullptr, allocator); } diff --git a/ets2panda/ir/statements/annotationDeclaration.h b/ets2panda/ir/statements/annotationDeclaration.h index f55f5914444081776373deae34dc9c13edd37b7c..b9c7f81d7ca6615ae9acc72695eda156cfced611 100644 --- a/ets2panda/ir/statements/annotationDeclaration.h +++ b/ets2panda/ir/statements/annotationDeclaration.h @@ -42,42 +42,38 @@ public: expr_(expr), properties_(allocator->Adapter()) { + EnableHistory(); } explicit AnnotationDeclaration(Expression *expr, ArenaVector &&properties, ArenaAllocator *allocator) : AnnotationAllowed(AstNodeType::ANNOTATION_DECLARATION, allocator), expr_(expr), properties_(std::move(properties)) { + EnableHistory(); } const util::StringView &InternalName() const { - return internalName_; + RETURN_GET(AnnotationDeclaration, internalName_); } - void SetInternalName(util::StringView internalName) - { - internalName_ = internalName; - } + void SetInternalName(util::StringView source); [[nodiscard]] const Expression *Expr() const noexcept { - return expr_; + RETURN_GET(AnnotationDeclaration, expr_); } [[nodiscard]] Expression *Expr() noexcept { - return expr_; + RETURN_GET(AnnotationDeclaration, expr_); } - [[nodiscard]] ArenaVector &Properties() noexcept - { - return properties_; - } + [[nodiscard]] ArenaVector &Properties(); [[nodiscard]] const ArenaVector &Properties() const noexcept { - return properties_; + RETURN_GET(AnnotationDeclaration, properties_); } [[nodiscard]] const ArenaVector *PropertiesPtr() const @@ -87,37 +83,41 @@ public: void AddProperties(ArenaVector &&properties) { - properties_ = std::move(properties); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + ; + ; + CHANGEABLE_SET_CHILD(newNode); + newNode->properties_ = std::move(properties); } [[nodiscard]] bool IsSourceRetention() const noexcept { - return (policy_ & RetentionPolicy::SOURCE) != 0; + return (Policy() & RetentionPolicy::SOURCE) != 0; } [[nodiscard]] bool IsBytecodeRetention() const noexcept { - return (policy_ & RetentionPolicy::BYTECODE) != 0; + return (Policy() & RetentionPolicy::BYTECODE) != 0; } [[nodiscard]] bool IsRuntimeRetention() const noexcept { - return (policy_ & RetentionPolicy::RUNTIME) != 0; + return (Policy() & RetentionPolicy::RUNTIME) != 0; } void SetSourceRetention() noexcept { - policy_ = RetentionPolicy::SOURCE; + GetOrCreateHistoryNodeAs()->policy_ = RetentionPolicy::SOURCE; } void SetBytecodeRetention() noexcept { - policy_ = RetentionPolicy::BYTECODE; + GetOrCreateHistoryNodeAs()->policy_ = RetentionPolicy::BYTECODE; } void SetRuntimeRetention() noexcept { - policy_ = RetentionPolicy::RUNTIME; + GetOrCreateHistoryNodeAs()->policy_ = RetentionPolicy::RUNTIME; } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -141,28 +141,37 @@ public: [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override { - return scope_; + RETURN_GET(AnnotationDeclaration, scope_); } void SetScope(varbinder::LocalScope *scope) { ES2PANDA_ASSERT(scope_ == nullptr); - scope_ = scope; + GetOrCreateHistoryNodeAs()->scope_ = scope; } void ClearScope() noexcept override { - scope_ = nullptr; + GetOrCreateHistoryNodeAs()->scope_ = nullptr; } Identifier *GetBaseName() const; -protected: - AstNode *Construct(ArenaAllocator *allocator) override; + void EmplaceProperties(AstNode *source); + void ClearProperties(); + void SetValueProperties(AstNode *source, size_t index); + + AnnotationDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; private: - friend class SizeOfNodeTest; + RetentionPolicy Policy() const + { + RETURN_GET(AnnotationDeclaration, policy_); + } + + void SetExpr(Expression *source); + util::StringView internalName_ {}; varbinder::LocalScope *scope_ {}; Expression *expr_; diff --git a/ets2panda/ir/statements/blockStatement.cpp b/ets2panda/ir/statements/blockStatement.cpp index 63cc1287f0571f3ae1827238d251afd1214c8936..abbe7d12b09e925f5b0f41b78027bab834556bc6 100644 --- a/ets2panda/ir/statements/blockStatement.cpp +++ b/ets2panda/ir/statements/blockStatement.cpp @@ -28,11 +28,13 @@ namespace ark::es2panda::ir { void BlockStatement::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { // This will survive pushing element to the back of statements_ in the process - // NOLINTNEXTLINE(modernize-loop-convert) - for (size_t ix = 0; ix < statements_.size(); ix++) { - if (auto *transformedNode = cb(statements_[ix]); statements_[ix] != transformedNode) { - statements_[ix]->SetTransformedNode(transformationName, transformedNode); - statements_[ix] = transformedNode->AsStatement(); + auto const &constStatements = Statements(); + for (size_t index = 0; index < constStatements.size(); index++) { + auto statement = constStatements[index]; + if (auto *transformedNode = cb(statement); statement != transformedNode) { + statement->SetTransformedNode(transformationName, transformedNode); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + statements[index] = transformedNode->AsStatement(); } } } @@ -41,7 +43,7 @@ AstNode *BlockStatement::Clone(ArenaAllocator *const allocator, AstNode *const p { ArenaVector statements(allocator->Adapter()); - for (auto *statement : this->statements_) { + for (auto *statement : Statements()) { statements.push_back(statement->Clone(allocator, parent)->AsStatement()); } @@ -54,35 +56,37 @@ AstNode *BlockStatement::Clone(ArenaAllocator *const allocator, AstNode *const p void BlockStatement::Iterate(const NodeTraverser &cb) const { // This will survive pushing element to the back of statements_ in the process + auto const &statements = Statements(); // NOLINTNEXTLINE(modernize-loop-convert) - for (size_t ix = 0; ix < statements_.size(); ix++) { - cb(statements_[ix]); + for (size_t ix = 0; ix < statements.size(); ix++) { + cb(statements[ix]); } } void BlockStatement::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", IsProgram() ? "Program" : "BlockStatement"}, {"statements", statements_}}); + dumper->Add({{"type", IsProgram() ? "Program" : "BlockStatement"}, {"statements", Statements()}}); } void BlockStatement::Dump(ir::SrcDumper *dumper) const { + auto const &statements = Statements(); // NOTE(nsizov): trailing blocks if (Parent() != nullptr && (Parent()->IsBlockStatement() || Parent()->IsCallExpression())) { dumper->Add("{"); - if (!statements_.empty()) { + if (!statements.empty()) { dumper->IncrIndent(); dumper->Endl(); } } - for (auto statement : statements_) { + for (auto statement : statements) { statement->Dump(dumper); - if (statement != statements_.back()) { + if (statement != statements.back()) { dumper->Endl(); } } if (Parent() != nullptr && (Parent()->IsBlockStatement() || Parent()->IsCallExpression())) { - if (!statements_.empty()) { + if (!statements.empty()) { dumper->DecrIndent(); dumper->Endl(); } @@ -118,7 +122,7 @@ BlockStatement *BlockStatement::Construct(ArenaAllocator *allocator) void BlockStatement::CopyTo(AstNode *other) const { - auto otherImpl = other->AsBlockStatement(); + auto otherImpl = static_cast(other); otherImpl->scope_ = scope_; otherImpl->statements_ = statements_; diff --git a/ets2panda/ir/statements/blockStatement.h b/ets2panda/ir/statements/blockStatement.h index 81745d7f37bb22b6840257ad042f9524b6eb6b1b..0789e2aa8ec46d75cf1c413f3557da22d390180a 100644 --- a/ets2panda/ir/statements/blockStatement.h +++ b/ets2panda/ir/statements/blockStatement.h @@ -31,11 +31,9 @@ public: statements_(std::move(statementList)), trailingBlocks_(allocator->Adapter()) { + EnableHistory(); } - // NOTE (somas): this friend relationship can be removed once there are getters for private fields - friend class checker::ETSAnalyzer; - [[nodiscard]] bool IsScopeBearer() const noexcept override { return true; @@ -43,55 +41,92 @@ public: [[nodiscard]] varbinder::Scope *Scope() const noexcept override { - return scope_; + return AstNode::GetHistoryNodeAs()->scope_; } void SetScope(varbinder::Scope *scope) noexcept { - scope_ = scope; + if (Scope() != scope) { + AstNode::GetOrCreateHistoryNodeAs()->scope_ = scope; + } } void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } - const ArenaVector &Statements() const + ArenaVector &StatmentsForUpdates() { - return statements_; + //ES2PANDA_ASSERT(!AstNode::CheckProgramLowered(this)); + return AstNode::GetOrCreateHistoryNodeAs()->statements_; } - ArenaVector &Statements() + const ArenaVector &Statements() { - return statements_; + return AstNode::GetHistoryNodeAs()->statements_; + } + + const ArenaVector &Statements() const + { + return AstNode::GetHistoryNodeAs()->statements_; } void SetStatements(ArenaVector &&statementList) { - statements_ = std::move(statementList); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + statements = std::move(statementList); - for (auto *statement : statements_) { + for (auto *statement : Statements()) { statement->SetParent(this); } } - void AddStatement(Statement *stmt) + void AddStatements(const ArenaVector &statementList) { - stmt->SetParent(this); - statements_.emplace_back(stmt); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + + for (auto statement : statementList) { + statement->SetParent(this); + statements.emplace_back(statement); + } } - void AddStatements(ArenaVector &stmts) + void ClearStatements() { - for (auto *stmt : stmts) { - stmt->SetParent(this); - } - statements_.insert(statements_.end(), stmts.begin(), stmts.end()); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + statements.clear(); + } + + void AddStatement(Statement *statement) + { + statement->SetParent(this); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + statements.emplace_back(statement); + } + + void AddStatement(std::size_t idx, Statement *statement) + { + statement->SetParent(this); + auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; + statements.emplace(std::next(statements.begin() + idx),statement); } void AddTrailingBlock(AstNode *stmt, BlockStatement *trailingBlock) { - trailingBlocks_.emplace(stmt, trailingBlock); + AstNode::GetOrCreateHistoryNodeAs()->trailingBlocks_.emplace(stmt, trailingBlock); + } + + BlockStatement *SearchStatementInTrailingBlock(Statement *item) + { + auto &trailingBlock = AstNode::GetHistoryNodeAs()->trailingBlocks_; + auto nowNode = item->GetHistoryNode(); + for (auto &it : trailingBlock) { + if (it.first->GetHistoryNode() == nowNode) { + return it.second; + } + } + return nullptr; } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; diff --git a/ets2panda/ir/statements/classDeclaration.cpp b/ets2panda/ir/statements/classDeclaration.cpp index d459bc5e20c5bdcb57fb1b78d4a94c5f7f1d7a37..7b0763e119b33d9f942f878a91dc0f0a999bacc9 100644 --- a/ets2panda/ir/statements/classDeclaration.cpp +++ b/ets2panda/ir/statements/classDeclaration.cpp @@ -24,6 +24,10 @@ namespace ark::es2panda::ir { +SETTER_FOR_CHILD(ClassDeclaration, Definition, def_, ClassDefinition *); + +SETTER_FOR_ARENAVECTOR_CHILD(ClassDeclaration, Decorators, decorators_, Decorator *); + ClassDeclaration *ClassDeclaration::Construct(ArenaAllocator *allocator) { return allocator->New(nullptr, allocator); @@ -31,7 +35,7 @@ ClassDeclaration *ClassDeclaration::Construct(ArenaAllocator *allocator) void ClassDeclaration::CopyTo(AstNode *other) const { - auto otherImpl = other->AsClassDeclaration(); + auto otherImpl = reinterpret_cast(other); otherImpl->def_ = def_; otherImpl->decorators_ = decorators_; @@ -41,40 +45,45 @@ void ClassDeclaration::CopyTo(AstNode *other) const void ClassDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - if (auto *transformedNode = cb(def_); def_ != transformedNode) { - def_->SetTransformedNode(transformationName, transformedNode); - def_ = transformedNode->AsClassDefinition(); + auto const def = Definition(); + if (auto *transformedNode = cb(def); def != transformedNode) { + def->SetTransformedNode(transformationName, transformedNode); + SetDefinition(transformedNode->AsClassDefinition()); } } void ClassDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } - cb(def_); + auto def = GetHistoryNodeAs()->def_; + cb(def); } void ClassDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ClassDeclaration"}, {"definition", def_}, {"decorators", AstDumper::Optional(decorators_)}}); + dumper->Add({{"type", "ClassDeclaration"}, + {"definition", Definition()}, + {"decorators", AstDumper::Optional(Decorators())}}); } void ClassDeclaration::Dump(ir::SrcDumper *dumper) const { - if (def_ != nullptr) { - def_->Dump(dumper); + if (Definition() != nullptr) { + Definition()->Dump(dumper); } // NOTE(nsizov): support decorators when supported in ArkTS - ES2PANDA_ASSERT(decorators_.empty()); + ES2PANDA_ASSERT(Decorators().empty()); } void ClassDeclaration::Compile(compiler::PandaGen *pg) const diff --git a/ets2panda/ir/statements/classDeclaration.h b/ets2panda/ir/statements/classDeclaration.h index 72a5afe51f3c87fd15474be29ba37ffaa7e29358..79646dff935a50b9eefc50d9b4439a23f7a2b4f3 100644 --- a/ets2panda/ir/statements/classDeclaration.h +++ b/ets2panda/ir/statements/classDeclaration.h @@ -24,31 +24,39 @@ public: explicit ClassDeclaration(ClassDefinition *def, ArenaAllocator *allocator) : Statement(AstNodeType::CLASS_DECLARATION), def_(def), decorators_(allocator->Adapter()) { + EnableHistory(); } - ClassDefinition *Definition() + explicit ClassDeclaration(ClassDefinition *def, ArenaAllocator *allocator, AstNodeHistory *history) + : Statement(AstNodeType::CLASS_DECLARATION), def_(def), decorators_(allocator->Adapter()) { - return def_; + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } - const ClassDefinition *Definition() const + ClassDefinition *Definition() { - return def_; + RETURN_GET(ClassDeclaration, def_); } - const ArenaVector &Decorators() const + const ClassDefinition *Definition() const { - return decorators_; + RETURN_GET(ClassDeclaration, def_); } - const ArenaVector *DecoratorsPtr() const override + const ArenaVector &Decorators() const { - return &Decorators(); + RETURN_GET(ClassDeclaration, decorators_); } void AddDecorators(ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = GetOrCreateHistoryNodeAs(); + CHANGEABLE_SET_CHILD(newNode); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -71,10 +79,18 @@ public: v->Accept(this); } + void EmplaceDecorators(Decorator *source); + void ClearDecorators(); + void SetValueDecorators(Decorator *source, size_t index); + ArenaVector &Decorators(); + + void SetDefinition(ClassDefinition *source); + protected: explicit ClassDeclaration(AstNodeType type, ClassDefinition *const def, ArenaAllocator *const allocator) : Statement(type), def_(def), decorators_(allocator->Adapter()) { + EnableHistory(); } ClassDeclaration *Construct(ArenaAllocator *allocator) override; @@ -83,6 +99,7 @@ protected: private: friend class SizeOfNodeTest; + ClassDefinition *def_; ArenaVector decorators_; }; diff --git a/ets2panda/ir/statements/functionDeclaration.cpp b/ets2panda/ir/statements/functionDeclaration.cpp index 21fb0d5f85eea44a9eec9cc135d0589c74b4b153..250a2d83705c618dfe3d0717a67e1c8136d7d5b8 100644 --- a/ets2panda/ir/statements/functionDeclaration.cpp +++ b/ets2panda/ir/statements/functionDeclaration.cpp @@ -23,31 +23,33 @@ #include "compiler/core/pandagen.h" namespace ark::es2panda::ir { + +SETTER_FOR_CHILD(FunctionDeclaration, Function, func_, ScriptFunction *); + +SETTER_FOR_ARENAVECTOR_CHILD(FunctionDeclaration, Decorators, decorators_, Decorator *); + void FunctionDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); - if (auto *transformedNode = cb(func_); func_ != transformedNode) { - func_->SetTransformedNode(transformationName, transformedNode); - func_ = transformedNode->AsScriptFunction(); + auto const func = Function(); + if (auto *transformedNode = cb(func); func != transformedNode) { + func->SetTransformedNode(transformationName, transformedNode); + SetFunction(transformedNode->AsScriptFunction()); } } void FunctionDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } @@ -55,15 +57,16 @@ void FunctionDeclaration::Iterate(const NodeTraverser &cb) const cb(it); } - cb(func_); + auto func = GetHistoryNode()->AsFunctionDeclaration()->func_; + cb(func); } void FunctionDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", func_->IsOverload() ? "TSDeclareFunction" : "FunctionDeclaration"}, - {"decorators", AstDumper::Optional(decorators_)}, + dumper->Add({{"type", Function()->IsOverload() ? "TSDeclareFunction" : "FunctionDeclaration"}, + {"decorators", AstDumper::Optional(Decorators())}, {"annotations", AstDumper::Optional(Annotations())}, - {"function", func_}}); + {"function", Function()}}); } void FunctionDeclaration::Dump(ir::SrcDumper *dumper) const @@ -71,19 +74,20 @@ void FunctionDeclaration::Dump(ir::SrcDumper *dumper) const for (auto *anno : Annotations()) { anno->Dump(dumper); } - if (func_->IsNative()) { + auto func = Function(); + if (func->IsNative()) { dumper->Add("native "); } - if (func_->IsDeclare()) { + if (func->IsDeclare()) { dumper->Add("declare "); } - if (func_->IsAsyncFunc()) { + if (func->IsAsyncFunc()) { dumper->Add("async "); } dumper->Add("function "); - func_->Id()->Dump(dumper); - func_->Dump(dumper); + func->Id()->Dump(dumper); + func->Dump(dumper); } void FunctionDeclaration::Compile(compiler::PandaGen *pg) const diff --git a/ets2panda/ir/statements/functionDeclaration.h b/ets2panda/ir/statements/functionDeclaration.h index 55a3443f02a6ce3fe368bab929b555660767d4b3..7fe68533917a4ec65f31592109d714073977e99a 100644 --- a/ets2panda/ir/statements/functionDeclaration.h +++ b/ets2panda/ir/statements/functionDeclaration.h @@ -36,7 +36,10 @@ public: func_(func), isAnonymous_(isAnonymous) { - flags_ = func->Modifiers(); + EnableHistory(); + if (func != nullptr) { + flags_ = func->Modifiers(); + } } explicit FunctionDeclaration(ArenaAllocator *allocator, ScriptFunction *func, bool isAnonymous = false) @@ -45,27 +48,46 @@ public: func_(func), isAnonymous_(isAnonymous) { - flags_ = func->Modifiers(); + EnableHistory(); + if (func != nullptr) { + flags_ = func->Modifiers(); + } + } + + explicit FunctionDeclaration(ArenaAllocator *allocator, ScriptFunction *func, bool isAnonymous, + AstNodeHistory *history) + : JsDocAllowed>(AstNodeType::FUNCTION_DECLARATION, allocator), + decorators_(allocator->Adapter()), + func_(func), + isAnonymous_(isAnonymous) + { + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } ScriptFunction *Function() { - return func_; + RETURN_GET(FunctionDeclaration, func_); } bool IsAnonymous() const { - return isAnonymous_; + RETURN_GET(FunctionDeclaration, isAnonymous_); } const ScriptFunction *Function() const { - return func_; + RETURN_GET(FunctionDeclaration, func_); } void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = this->GetOrCreateHistoryNode()->AsFunctionDeclaration(); + CHANGEABLE_SET_CHILD(newNode); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -90,8 +112,19 @@ public: FunctionDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; + [[nodiscard]] const ArenaVector &Decorators() const + { + RETURN_GET(FunctionDeclaration, decorators_); + }; + private: friend class SizeOfNodeTest; + void SetFunction(ScriptFunction *source); + void EmplaceDecorators(Decorator *source); + void ClearDecorators(); + void SetValueDecorators(Decorator *source, size_t index); + [[nodiscard]] ArenaVector &Decorators(); + ArenaVector decorators_; ScriptFunction *func_; bool isAnonymous_; diff --git a/ets2panda/ir/statements/variableDeclaration.cpp b/ets2panda/ir/statements/variableDeclaration.cpp index 56934876cfc09ba4846b2df06ab28c70542f155b..d24828f17eb280a0f3b0220b7e49a5800644cca3 100644 --- a/ets2panda/ir/statements/variableDeclaration.cpp +++ b/ets2panda/ir/statements/variableDeclaration.cpp @@ -22,33 +22,40 @@ #include "utils/arena_containers.h" namespace ark::es2panda::ir { + +SETTER_FOR_ARENAVECTOR_CHILD(VariableDeclaration, Decorators, decorators_, Decorator *); +SETTER_FOR_ARENAVECTOR_CHILD(VariableDeclaration, Declarators, declarators_, VariableDeclarator *); + void VariableDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t index = 0; index < decorators.size(); ++index) { + if (auto *transformedNode = cb(decorators[index]); decorators[index] != transformedNode) { + decorators[index]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), index); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); + auto const &annotations = Annotations(); + for (size_t index = 0; index < annotations.size(); ++index) { + if (auto *transformedNode = cb(annotations[index]); annotations[index] != transformedNode) { + annotations[index]->SetTransformedNode(transformationName, transformedNode); + SetValueAnnotations(transformedNode->AsAnnotationUsage(), index); } } - for (auto *&it : VectorIterationGuard(declarators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsVariableDeclarator(); + auto const &declarators = Declarators(); + for (size_t index = 0; index < declarators.size(); ++index) { + if (auto *transformedNode = cb(declarators[index]); declarators[index] != transformedNode) { + declarators[index]->SetTransformedNode(transformationName, transformedNode); + SetValueDeclarators(transformedNode->AsVariableDeclarator(), index); } } } void VariableDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } @@ -56,7 +63,7 @@ void VariableDeclaration::Iterate(const NodeTraverser &cb) const cb(it); } - for (auto *it : VectorIterationGuard(declarators_)) { + for (auto *it : VectorIterationGuard(Declarators())) { cb(it); } } @@ -65,7 +72,7 @@ void VariableDeclaration::Dump(ir::AstDumper *dumper) const { const char *kind = nullptr; - switch (kind_) { + switch (Kind()) { case VariableDeclarationKind::CONST: { kind = "const"; break; @@ -84,9 +91,9 @@ void VariableDeclaration::Dump(ir::AstDumper *dumper) const } dumper->Add({{"type", "VariableDeclaration"}, - {"declarations", declarators_}, + {"declarations", Declarators()}, {"kind", kind}, - {"decorators", AstDumper::Optional(decorators_)}, + {"decorators", AstDumper::Optional(Decorators())}, {"annotations", AstDumper::Optional(Annotations())}, {"declare", AstDumper::Optional(IsDeclare())}}); } @@ -101,7 +108,7 @@ void VariableDeclaration::Dump(ir::SrcDumper *dumper) const dumper->Add("declare "); } - switch (kind_) { + switch (Kind()) { case VariableDeclarationKind::CONST: dumper->Add("const "); break; @@ -115,15 +122,16 @@ void VariableDeclaration::Dump(ir::SrcDumper *dumper) const ES2PANDA_UNREACHABLE(); } - for (auto declarator : declarators_) { + for (auto declarator : Declarators()) { declarator->Dump(dumper); - if (declarator != declarators_.back()) { + if (declarator != Declarators().back()) { dumper->Add(", "); } } - if ((parent_ != nullptr) && - (parent_->IsBlockStatement() || parent_->IsBlockExpression() || parent_->IsSwitchCaseStatement())) { + auto const parent = Parent(); + if ((parent != nullptr) && + (parent->IsBlockStatement() || parent->IsBlockExpression() || parent->IsSwitchCaseStatement())) { dumper->Add(";"); } } @@ -145,6 +153,33 @@ VariableDeclaration::VariableDeclaration([[maybe_unused]] Tag const tag, Variabl declarators_.emplace_back(d->Clone(allocator, nullptr)->AsVariableDeclarator()); declarators_.back()->SetParent(this); } + + EnableHistory(); +} + +VariableDeclaration::VariableDeclaration([[maybe_unused]] Tag const tag, VariableDeclaration const &other, + ArenaAllocator *const allocator, AstNodeHistory *history) + : JsDocAllowed>( + static_cast> const &>(other)), + kind_(other.kind_), + decorators_(allocator->Adapter()), + declarators_(allocator->Adapter()) +{ + for (auto const &d : other.decorators_) { + decorators_.emplace_back(d->Clone(allocator, nullptr)); + decorators_.back()->SetParent(this); + } + + for (auto const &d : other.declarators_) { + declarators_.emplace_back(d->Clone(allocator, nullptr)->AsVariableDeclarator()); + declarators_.back()->SetParent(this); + } + + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } VariableDeclaration *VariableDeclaration::Clone(ArenaAllocator *const allocator, AstNode *const parent) @@ -153,7 +188,7 @@ VariableDeclaration *VariableDeclaration::Clone(ArenaAllocator *const allocator, if (parent != nullptr) { clone->SetParent(parent); } - clone->SetRange(range_); + clone->SetRange(Range()); return clone; } diff --git a/ets2panda/ir/statements/variableDeclaration.h b/ets2panda/ir/statements/variableDeclaration.h index 7b3f8a58040eb42504a3b93498c06e18c63fbeae..660c1a44c9425d780298b6d2c8c0334367ef900e 100644 --- a/ets2panda/ir/statements/variableDeclaration.h +++ b/ets2panda/ir/statements/variableDeclaration.h @@ -40,28 +40,50 @@ public: decorators_(allocator->Adapter()), declarators_(std::move(declarators)) { + EnableHistory(); + } + + explicit VariableDeclaration(VariableDeclarationKind kind, ArenaAllocator *allocator, + ArenaVector &&declarators, AstNodeHistory *history) + : JsDocAllowed>(AstNodeType::VARIABLE_DECLARATION, allocator), + kind_(kind), + decorators_(allocator->Adapter()), + declarators_(std::move(declarators)) + { + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } explicit VariableDeclaration(Tag tag, VariableDeclaration const &other, ArenaAllocator *allocator); + explicit VariableDeclaration(Tag const tag, VariableDeclaration const &other, ArenaAllocator *const allocator, + AstNodeHistory *history); + const ArenaVector &Declarators() const { - return declarators_; + RETURN_GET(VariableDeclaration, declarators_); } + [[nodiscard]] ArenaVector &Declarators(); + VariableDeclarationKind Kind() const { - return kind_; + RETURN_GET(VariableDeclaration, kind_); } const ArenaVector &Decorators() const { - return decorators_; + RETURN_GET(VariableDeclaration, decorators_); } + [[nodiscard]] ArenaVector &Decorators(); + VariableDeclarator *GetDeclaratorByName(util::StringView name) const { - for (VariableDeclarator *declarator : declarators_) { + for (VariableDeclarator *declarator : Declarators()) { if (declarator->Id()->AsIdentifier()->Name().Compare(name) == 0) { return declarator; } @@ -69,14 +91,11 @@ public: return nullptr; } - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); - } - void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -105,6 +124,13 @@ public: private: friend class SizeOfNodeTest; + void SetValueDecorators(Decorator *source, size_t index); + void SetValueDeclarators(VariableDeclarator *source, size_t index); + void EmplaceDecorators(Decorator *source); + void ClearDecorators(); + void EmplaceDeclarators(VariableDeclarator *source); + void ClearDeclarators(); + VariableDeclarationKind kind_; ArenaVector decorators_; ArenaVector declarators_; diff --git a/ets2panda/ir/ts/tsAnyKeyword.cpp b/ets2panda/ir/ts/tsAnyKeyword.cpp index 99f5e085a28376e4526ed45b7f19aa3310a3ea5e..f8cde5748f2ff69663acb4834df7daa048b98993 100644 --- a/ets2panda/ir/ts/tsAnyKeyword.cpp +++ b/ets2panda/ir/ts/tsAnyKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSAnyKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSAnyKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsArrayType.cpp b/ets2panda/ir/ts/tsArrayType.cpp index 8a1e1abd2c4686b611869ca614b316e76b91a2bd..8ab2361fb9039274516edac8ef14f3d914e4b5f2 100644 --- a/ets2panda/ir/ts/tsArrayType.cpp +++ b/ets2panda/ir/ts/tsArrayType.cpp @@ -27,12 +27,8 @@ void TSArrayType::TransformChildren(const NodeTransformer &cb, std::string_view elementType_->SetTransformedNode(transformationName, transformedNode); elementType_ = static_cast(transformedNode); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSArrayType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsBigintKeyword.cpp b/ets2panda/ir/ts/tsBigintKeyword.cpp index 7b42542a7d28362c1530c0b2cacba43e622808d9..0e6a288d941bca5c137af32f77163e961a49ac31 100644 --- a/ets2panda/ir/ts/tsBigintKeyword.cpp +++ b/ets2panda/ir/ts/tsBigintKeyword.cpp @@ -26,12 +26,7 @@ namespace ark::es2panda::ir { void TSBigintKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSBigintKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsBooleanKeyword.cpp b/ets2panda/ir/ts/tsBooleanKeyword.cpp index 4d5b6f018a6dbd9e2b123638e92b7025beba62a5..bae3ac4ae1e718ae4b90c99062bb9beb761f0568 100644 --- a/ets2panda/ir/ts/tsBooleanKeyword.cpp +++ b/ets2panda/ir/ts/tsBooleanKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSBooleanKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSBooleanKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsConditionalType.cpp b/ets2panda/ir/ts/tsConditionalType.cpp index 6a70708b5c7e42df54454fdf5222eb42dedf9561..6a166ea3f06d02257c0994ce89bcfb8fba60fed6 100644 --- a/ets2panda/ir/ts/tsConditionalType.cpp +++ b/ets2panda/ir/ts/tsConditionalType.cpp @@ -43,12 +43,8 @@ void TSConditionalType::TransformChildren(const NodeTransformer &cb, std::string falseType_->SetTransformedNode(transformationName, transformedNode); falseType_ = transformedNode->AsExpression(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSConditionalType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsConstructorType.cpp b/ets2panda/ir/ts/tsConstructorType.cpp index 681161a310c8b4e1cb0938d6a0632ee5f96ca22f..327034616d33391c9db631e2518339ae51360301 100644 --- a/ets2panda/ir/ts/tsConstructorType.cpp +++ b/ets2panda/ir/ts/tsConstructorType.cpp @@ -26,12 +26,7 @@ namespace ark::es2panda::ir { void TSConstructorType::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { signature_.TransformChildren(cb, transformationName); - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSConstructorType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsEnumDeclaration.cpp b/ets2panda/ir/ts/tsEnumDeclaration.cpp index 42603eda1e26e930bce2ce4b083fc0a19d4f947a..d8410922669962a3941dbe450c1a4cae6981e030 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.cpp +++ b/ets2panda/ir/ts/tsEnumDeclaration.cpp @@ -25,37 +25,50 @@ #include "utils/arena_containers.h" namespace ark::es2panda::ir { + +SETTER_FOR_FIELD(TSEnumDeclaration, InternalName, internalName_, util::StringView); + +SETTER_FOR_CHILD(TSEnumDeclaration, BoxedClass, boxedClass_, ClassDefinition *); +SETTER_FOR_CHILD(TSEnumDeclaration, Key, key_, Identifier *); + +SETTER_FOR_ARENAVECTOR_CHILD(TSEnumDeclaration, Decorators, decorators_, Decorator *); +SETTER_FOR_ARENAVECTOR_CHILD(TSEnumDeclaration, Members, members_, AstNode *); + void TSEnumDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - if (auto *transformedNode = cb(key_); key_ != transformedNode) { - key_->SetTransformedNode(transformationName, transformedNode); - key_ = transformedNode->AsIdentifier(); + auto const key = Key(); + if (auto *transformedNode = cb(key); key != transformedNode) { + key->SetTransformedNode(transformationName, transformedNode); + SetKey(transformedNode->AsIdentifier()); } - for (auto *&it : VectorIterationGuard(members_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode; + auto const &members = Members(); + for (size_t ix = 0; ix < members.size(); ix++) { + if (auto *transformedNode = cb(members[ix]); members[ix] != transformedNode) { + members[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueMembers(transformedNode->AsDecorator(), ix); } } } void TSEnumDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } - cb(key_); + auto const key = GetHistoryNode()->AsTSEnumDeclaration()->key_; + cb(key); - for (auto *it : VectorIterationGuard(members_)) { + for (auto *it : VectorIterationGuard(Members())) { cb(it); } } @@ -63,10 +76,10 @@ void TSEnumDeclaration::Iterate(const NodeTraverser &cb) const void TSEnumDeclaration::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "TSEnumDeclaration"}, - {"decorators", AstDumper::Optional(decorators_)}, - {"id", key_}, - {"members", members_}, - {"const", isConst_}, + {"decorators", AstDumper::Optional(Decorators())}, + {"id", Key()}, + {"members", Members()}, + {"const", IsConst()}, {"declare", IsDeclare()}}); } @@ -105,14 +118,15 @@ void TSEnumDeclaration::Dump(ir::SrcDumper *dumper) const dumper->Add("declare "); } dumper->Add("enum "); - key_->Dump(dumper); + Key()->Dump(dumper); dumper->Add(" {"); - if (!members_.empty()) { + auto const members = Members(); + if (!members.empty()) { dumper->IncrIndent(); dumper->Endl(); - for (auto member : members_) { + for (auto member : members) { member->Dump(dumper); - if (member != members_.back()) { + if (member != members.back()) { dumper->Add(","); dumper->Endl(); } diff --git a/ets2panda/ir/ts/tsEnumDeclaration.h b/ets2panda/ir/ts/tsEnumDeclaration.h index ffb58b61536cfdfc6e0843bf0c50a0fba1ec0765..1e11e5a2dd107c5762ae5bc75ccf8978afbc9f20 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.h +++ b/ets2panda/ir/ts/tsEnumDeclaration.h @@ -52,6 +52,28 @@ public: if (flags.isDeclare) { AddModifier(ModifierFlags::DECLARE); } + EnableHistory(); + } + + explicit TSEnumDeclaration(ArenaAllocator *allocator, Identifier *key, ArenaVector &&members, + ConstructorFlags &&flags, AstNodeHistory *history) + : TypedStatement(AstNodeType::TS_ENUM_DECLARATION), + decorators_(allocator->Adapter()), + key_(key), + members_(std::move(members)), + isConst_(flags.isConst) + { + if (flags.isStatic) { + AddModifier(ModifierFlags::STATIC); + } + if (flags.isDeclare) { + AddModifier(ModifierFlags::DECLARE); + } + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } [[nodiscard]] bool IsScopeBearer() const noexcept override @@ -61,73 +83,64 @@ public: [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override { - return scope_; + RETURN_GET(TSEnumDeclaration, scope_); } void SetScope(varbinder::LocalScope *scope) { - ES2PANDA_ASSERT(scope_ == nullptr); - scope_ = scope; + ES2PANDA_ASSERT(Scope() == nullptr); + GetOrCreateHistoryNode()->AsTSEnumDeclaration()->scope_ = scope; } void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } const Identifier *Key() const { - return key_; + RETURN_GET(TSEnumDeclaration, key_); } Identifier *Key() { - return key_; + RETURN_GET(TSEnumDeclaration, key_); } const ArenaVector &Members() const { - return members_; + RETURN_GET(TSEnumDeclaration, members_); } const util::StringView &InternalName() const { - return internalName_; + RETURN_GET(TSEnumDeclaration, internalName_); } - void SetInternalName(util::StringView internalName) - { - internalName_ = internalName; - } + void SetInternalName(util::StringView source); ir::ClassDefinition *BoxedClass() const { - return boxedClass_; + RETURN_GET(TSEnumDeclaration, boxedClass_); } - void SetBoxedClass(ir::ClassDefinition *const wrapperClass) - { - boxedClass_ = wrapperClass; - } + void SetBoxedClass(ir::ClassDefinition *source); bool IsConst() const { - return isConst_; + RETURN_GET(TSEnumDeclaration, isConst_); } const ArenaVector &Decorators() const { - return decorators_; - } - - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); + RETURN_GET(TSEnumDeclaration, decorators_); } void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = GetOrCreateHistoryNodeAs(); + CHANGEABLE_SET_CHILD(newNode); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -154,9 +167,21 @@ public: TSEnumDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; + void EmplaceDecorators(Decorator *source); + void ClearDecorators(); + void SetValueDecorators(Decorator *source, size_t index); + [[nodiscard]] ArenaVector &Decorators(); + + void EmplaceMembers(AstNode *source); + void ClearMembers(); + void SetValueMembers(AstNode *source, size_t index); + [[nodiscard]] ArenaVector &Members(); + private: bool RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const; friend class SizeOfNodeTest; + void SetKey(Identifier *source); + varbinder::LocalScope *scope_ {nullptr}; ArenaVector decorators_; Identifier *key_; diff --git a/ets2panda/ir/ts/tsFunctionType.cpp b/ets2panda/ir/ts/tsFunctionType.cpp index ed1698e0a2edce79a3efc37ae83f12304caac43d..89e4751aeb965dd49d3133f81e7346ea7512f16d 100644 --- a/ets2panda/ir/ts/tsFunctionType.cpp +++ b/ets2panda/ir/ts/tsFunctionType.cpp @@ -27,12 +27,7 @@ namespace ark::es2panda::ir { void TSFunctionType::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { signature_.TransformChildren(cb, transformationName); - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSFunctionType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsImportType.cpp b/ets2panda/ir/ts/tsImportType.cpp index 7854c7d3c87ae58d18c666de85a182d52ce5baef..a0f981b892b10daf920ba9c037d28d4acb2c6f8e 100644 --- a/ets2panda/ir/ts/tsImportType.cpp +++ b/ets2panda/ir/ts/tsImportType.cpp @@ -44,12 +44,8 @@ void TSImportType::TransformChildren(const NodeTransformer &cb, std::string_view qualifier_ = transformedNode->AsExpression(); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSImportType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsIndexedAccessType.cpp b/ets2panda/ir/ts/tsIndexedAccessType.cpp index f2d897be6e70072fe062d1be3229ffc7fee10d3c..e1e110231a601b905106b838db5c8fa0c83df80d 100644 --- a/ets2panda/ir/ts/tsIndexedAccessType.cpp +++ b/ets2panda/ir/ts/tsIndexedAccessType.cpp @@ -34,12 +34,8 @@ void TSIndexedAccessType::TransformChildren(const NodeTransformer &cb, std::stri indexType_->SetTransformedNode(transformationName, transformedNode); indexType_ = static_cast(transformedNode); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSIndexedAccessType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsInferType.cpp b/ets2panda/ir/ts/tsInferType.cpp index 5db886b2e48b4338edb27310374479ccf047ddcb..dd9d1746dcbcf30eef9bd39581a407ecd6e3bd70 100644 --- a/ets2panda/ir/ts/tsInferType.cpp +++ b/ets2panda/ir/ts/tsInferType.cpp @@ -29,12 +29,8 @@ void TSInferType::TransformChildren(const NodeTransformer &cb, std::string_view typeParam_->SetTransformedNode(transformationName, transformedNode); typeParam_ = transformedNode->AsTSTypeParameter(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSInferType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsInterfaceDeclaration.cpp b/ets2panda/ir/ts/tsInterfaceDeclaration.cpp index bea508e3884f802432be8774911b354036a61efb..69c948843eae09aab5474f3f1ed08092ed38c54e 100644 --- a/ets2panda/ir/ts/tsInterfaceDeclaration.cpp +++ b/ets2panda/ir/ts/tsInterfaceDeclaration.cpp @@ -34,50 +34,61 @@ #include "util/language.h" namespace ark::es2panda::ir { + +SETTER_FOR_FIELD(TSInterfaceDeclaration, InternalName, internalName_, util::StringView); + +SETTER_FOR_CHILD(TSInterfaceDeclaration, AnonClass, anonClass_, ClassDeclaration *); +SETTER_FOR_CHILD(TSInterfaceDeclaration, Id, id_, Identifier *); +SETTER_FOR_CHILD(TSInterfaceDeclaration, TypeParams, typeParams_, TSTypeParameterDeclaration *); +SETTER_FOR_CHILD(TSInterfaceDeclaration, Body, body_, TSInterfaceBody *); + +SETTER_FOR_ARENAVECTOR_CHILD(TSInterfaceDeclaration, Extends, extends_, TSInterfaceHeritage *); +SETTER_FOR_ARENAVECTOR_CHILD(TSInterfaceDeclaration, Decorators, decorators_, Decorator *); + void TSInterfaceDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - for (auto *&it : Annotations()) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); - if (auto *transformedNode = cb(id_); id_ != transformedNode) { - id_->SetTransformedNode(transformationName, transformedNode); - id_ = transformedNode->AsIdentifier(); + auto const id = Id(); + if (auto *transformedNode = cb(id); id != transformedNode) { + id->SetTransformedNode(transformationName, transformedNode); + SetId(transformedNode->AsIdentifier()); } - if (typeParams_ != nullptr) { - if (auto *transformedNode = cb(typeParams_); typeParams_ != transformedNode) { - typeParams_->SetTransformedNode(transformationName, transformedNode); - typeParams_ = transformedNode->AsTSTypeParameterDeclaration(); + auto const typeParams = TypeParams(); + if (typeParams != nullptr) { + if (auto *transformedNode = cb(typeParams); typeParams != transformedNode) { + typeParams->SetTransformedNode(transformationName, transformedNode); + SetTypeParams(transformedNode->AsTSTypeParameterDeclaration()); } } - for (auto *&it : VectorIterationGuard(extends_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsTSInterfaceHeritage(); + auto const &extends = Extends(); + for (size_t ix = 0; ix < extends.size(); ix++) { + if (auto *transformedNode = cb(extends[ix]); extends[ix] != transformedNode) { + extends[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueExtends(transformedNode->AsTSInterfaceHeritage(), ix); } } - if (auto *transformedNode = cb(body_); body_ != transformedNode) { - body_->SetTransformedNode(transformationName, transformedNode); - body_ = transformedNode->AsTSInterfaceBody(); + auto const &body = Body(); + if (auto *transformedNode = cb(body); body != transformedNode) { + body->SetTransformedNode(transformationName, transformedNode); + SetBody(transformedNode->AsTSInterfaceBody()); } } void TSInterfaceDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } @@ -85,28 +96,31 @@ void TSInterfaceDeclaration::Iterate(const NodeTraverser &cb) const cb(it); } - cb(id_); + auto const id = GetHistoryNode()->AsTSInterfaceDeclaration()->id_; + cb(id); - if (typeParams_ != nullptr) { - cb(typeParams_); + auto const typeParams = GetHistoryNode()->AsTSInterfaceDeclaration()->typeParams_; + if (typeParams != nullptr) { + cb(typeParams); } - for (auto *it : VectorIterationGuard(extends_)) { + for (auto *it : VectorIterationGuard(Extends())) { cb(it); } - cb(body_); + auto const body = GetHistoryNode()->AsTSInterfaceDeclaration()->body_; + cb(body); } void TSInterfaceDeclaration::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "TSInterfaceDeclaration"}, - {"decorators", AstDumper::Optional(decorators_)}, + {"decorators", AstDumper::Optional(Decorators())}, {"annotations", AstDumper::Optional(Annotations())}, - {"body", body_}, - {"id", id_}, - {"extends", extends_}, - {"typeParameters", AstDumper::Optional(typeParams_)}}); + {"body", Body()}, + {"id", Id()}, + {"extends", Extends()}, + {"typeParameters", AstDumper::Optional(TypeParams())}}); } bool TSInterfaceDeclaration::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const @@ -149,28 +163,32 @@ void TSInterfaceDeclaration::Dump(ir::SrcDumper *dumper) const dumper->Add("declare "); } dumper->Add("interface "); - id_->Dump(dumper); + Id()->Dump(dumper); - if (typeParams_ != nullptr) { + auto const typeParams = TypeParams(); + if (typeParams != nullptr) { dumper->Add("<"); - typeParams_->Dump(dumper); + typeParams->Dump(dumper); dumper->Add(">"); } - if (!extends_.empty()) { + + auto const extends = Extends(); + if (!extends.empty()) { dumper->Add(" extends "); - for (auto ext : extends_) { + for (auto ext : extends) { ext->Dump(dumper); - if (ext != extends_.back()) { + if (ext != extends.back()) { dumper->Add(", "); } } } + auto body = Body(); dumper->Add(" {"); - if (body_ != nullptr) { + if (body != nullptr) { dumper->IncrIndent(); dumper->Endl(); - body_->Dump(dumper); + body->Dump(dumper); dumper->DecrIndent(); dumper->Endl(); } diff --git a/ets2panda/ir/ts/tsInterfaceDeclaration.h b/ets2panda/ir/ts/tsInterfaceDeclaration.h index fb338b4c963b1f945b2cea71299ec20ff1f5b32a..a2e94bb3a934adab6903ffb9a8548003cb56a54b 100644 --- a/ets2panda/ir/ts/tsInterfaceDeclaration.h +++ b/ets2panda/ir/ts/tsInterfaceDeclaration.h @@ -58,6 +58,29 @@ public: if (isStatic_) { AddModifier(ir::ModifierFlags::STATIC); } + EnableHistory(); + } + + explicit TSInterfaceDeclaration(ArenaAllocator *allocator, ArenaVector &&extends, + ConstructorData &&data, AstNodeHistory *history) + : JsDocAllowed>(AstNodeType::TS_INTERFACE_DECLARATION, allocator), + decorators_(allocator->Adapter()), + id_(data.id), + typeParams_(data.typeParams), + body_(data.body), + extends_(std::move(extends)), + isStatic_(data.isStatic), + isExternal_(data.isExternal), + lang_(data.lang) + { + if (isStatic_) { + AddModifier(ir::ModifierFlags::STATIC); + } + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } [[nodiscard]] bool IsScopeBearer() const noexcept override @@ -67,93 +90,84 @@ public: [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override { - return scope_; + RETURN_GET(TSInterfaceDeclaration, scope_); } void SetScope(varbinder::LocalScope *scope) { - ES2PANDA_ASSERT(scope_ == nullptr); - scope_ = scope; + ES2PANDA_ASSERT(Scope() == nullptr); + GetOrCreateHistoryNode()->AsTSInterfaceDeclaration()->scope_ = scope; } void ClearScope() noexcept override { - scope_ = nullptr; + GetOrCreateHistoryNode()->AsTSInterfaceDeclaration()->scope_ = nullptr; } TSInterfaceBody *Body() { - return body_; + RETURN_GET(TSInterfaceDeclaration, body_); } const TSInterfaceBody *Body() const { - return body_; + RETURN_GET(TSInterfaceDeclaration, body_); } Identifier *Id() { - return id_; + RETURN_GET(TSInterfaceDeclaration, id_); } const Identifier *Id() const { - return id_; + RETURN_GET(TSInterfaceDeclaration, id_); } const util::StringView &InternalName() const { - return internalName_; + RETURN_GET(TSInterfaceDeclaration, internalName_); } - void SetInternalName(util::StringView internalName) - { - internalName_ = internalName; - } + void SetInternalName(util::StringView source); bool IsStatic() const { - return isStatic_; + RETURN_GET(TSInterfaceDeclaration, isStatic_); } bool IsFromExternal() const { - return isExternal_; + RETURN_GET(TSInterfaceDeclaration, isExternal_); } const TSTypeParameterDeclaration *TypeParams() const { - return typeParams_; + RETURN_GET(TSInterfaceDeclaration, typeParams_); } TSTypeParameterDeclaration *TypeParams() { - return typeParams_; + RETURN_GET(TSInterfaceDeclaration, typeParams_); } - ArenaVector &Extends() - { - return extends_; - } + [[nodiscard]] ArenaVector &Extends(); const ArenaVector &Extends() const { - return extends_; + RETURN_GET(TSInterfaceDeclaration, extends_); } const ArenaVector &Decorators() const { - return decorators_; - } - - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); + RETURN_GET(TSInterfaceDeclaration, decorators_); } void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -165,23 +179,20 @@ public: es2panda::Language Language() const { - return lang_; + RETURN_GET(TSInterfaceDeclaration, lang_); } ClassDeclaration *GetAnonClass() noexcept { - return anonClass_; + RETURN_GET(TSInterfaceDeclaration, anonClass_); } ClassDeclaration *GetAnonClass() const noexcept { - return anonClass_; + RETURN_GET(TSInterfaceDeclaration, anonClass_); } - void SetAnonClass(ClassDeclaration *anonClass) noexcept - { - anonClass_ = anonClass; - } + void SetAnonClass(ClassDeclaration *source); void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; @@ -200,9 +211,22 @@ public: TSInterfaceDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; + void EmplaceExtends(TSInterfaceHeritage *source); + void ClearExtends(); + void SetValueExtends(TSInterfaceHeritage *source, size_t index); + + void EmplaceDecorators(Decorator *source); + void ClearDecorators(); + void SetValueDecorators(Decorator *source, size_t index); + [[nodiscard]] ArenaVector &Decorators(); + private: bool RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const; friend class SizeOfNodeTest; + void SetId(Identifier *source); + void SetTypeParams(TSTypeParameterDeclaration *source); + void SetBody(TSInterfaceBody *source); + ArenaVector decorators_; varbinder::LocalScope *scope_ {nullptr}; Identifier *id_; diff --git a/ets2panda/ir/ts/tsIntersectionType.cpp b/ets2panda/ir/ts/tsIntersectionType.cpp index 75cf7834dcade735a58447e785512888d409d26b..6dc630a18a4c57e98d0250cdf88bddca4abed7b9 100644 --- a/ets2panda/ir/ts/tsIntersectionType.cpp +++ b/ets2panda/ir/ts/tsIntersectionType.cpp @@ -31,12 +31,8 @@ void TSIntersectionType::TransformChildren(const NodeTransformer &cb, std::strin it = transformedNode->AsExpression(); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSIntersectionType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsLiteralType.cpp b/ets2panda/ir/ts/tsLiteralType.cpp index 25a998cc1791d908f7facc7d9f5d9c691f4a4c7f..a679912bf4dbec77ce97320c56050f0a5e95b96b 100644 --- a/ets2panda/ir/ts/tsLiteralType.cpp +++ b/ets2panda/ir/ts/tsLiteralType.cpp @@ -28,12 +28,8 @@ void TSLiteralType::TransformChildren(const NodeTransformer &cb, std::string_vie literal_->SetTransformedNode(transformationName, transformedNode); literal_ = transformedNode->AsExpression(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSLiteralType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsMappedType.cpp b/ets2panda/ir/ts/tsMappedType.cpp index fef66f0e8c85bc1aea31752ed6cef2f431f55cf3..61da853b75b4d81a1f1d2f1f6cb77ddda83e1e78 100644 --- a/ets2panda/ir/ts/tsMappedType.cpp +++ b/ets2panda/ir/ts/tsMappedType.cpp @@ -37,12 +37,8 @@ void TSMappedType::TransformChildren(const NodeTransformer &cb, std::string_view typeAnnotation_ = static_cast(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSMappedType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsNamedTupleMember.cpp b/ets2panda/ir/ts/tsNamedTupleMember.cpp index d07fb3d98260186bfe3a8ed000a077d91a6fdd43..742f9e6cd4f251a3a5beac4026f986dc92e86cdf 100644 --- a/ets2panda/ir/ts/tsNamedTupleMember.cpp +++ b/ets2panda/ir/ts/tsNamedTupleMember.cpp @@ -34,12 +34,8 @@ void TSNamedTupleMember::TransformChildren(const NodeTransformer &cb, std::strin elementType_->SetTransformedNode(transformationName, transformedNode); elementType_ = static_cast(transformedNode); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSNamedTupleMember::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsNeverKeyword.cpp b/ets2panda/ir/ts/tsNeverKeyword.cpp index 9b1386dcad545c5d250185cda639b165eb18cecc..a48751933c6adcd2d9da89f246aed6d0f6a185a3 100644 --- a/ets2panda/ir/ts/tsNeverKeyword.cpp +++ b/ets2panda/ir/ts/tsNeverKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSNeverKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSNeverKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsNullKeyword.cpp b/ets2panda/ir/ts/tsNullKeyword.cpp index d7050a9ff3ce77c11cc906d752ddd93d90526fd7..6e089e142a4f464c021c8b07603eadc74e7d2cc9 100644 --- a/ets2panda/ir/ts/tsNullKeyword.cpp +++ b/ets2panda/ir/ts/tsNullKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSNullKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSNullKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsNumberKeyword.cpp b/ets2panda/ir/ts/tsNumberKeyword.cpp index 9c9125def9d5a883b776b0828c39aa386634b019..afcee6e7b57be49fbceed2b822755658ede6cfb5 100644 --- a/ets2panda/ir/ts/tsNumberKeyword.cpp +++ b/ets2panda/ir/ts/tsNumberKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSNumberKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSNumberKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsObjectKeyword.cpp b/ets2panda/ir/ts/tsObjectKeyword.cpp index fd807caf030fdb3257289bca399cff81bfcf81fe..3b4ea39d6e3ac55b1ae44e821b1418c6ce9794b1 100644 --- a/ets2panda/ir/ts/tsObjectKeyword.cpp +++ b/ets2panda/ir/ts/tsObjectKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSObjectKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSObjectKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsParenthesizedType.cpp b/ets2panda/ir/ts/tsParenthesizedType.cpp index 4ee640455b23b6b0bb5f5f9bc0b2e6d7de5bb346..4608efb394706a13363c6b93748cf1b8f4073207 100644 --- a/ets2panda/ir/ts/tsParenthesizedType.cpp +++ b/ets2panda/ir/ts/tsParenthesizedType.cpp @@ -28,12 +28,8 @@ void TSParenthesizedType::TransformChildren(const NodeTransformer &cb, std::stri type_->SetTransformedNode(transformationName, transformedNode); type_ = static_cast(transformedNode); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSParenthesizedType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsStringKeyword.cpp b/ets2panda/ir/ts/tsStringKeyword.cpp index 825b446bc4b07710cf009bc4f9f2064c28fb0720..be62a340044c1d0222feeb0fb32d75ad919a71d6 100644 --- a/ets2panda/ir/ts/tsStringKeyword.cpp +++ b/ets2panda/ir/ts/tsStringKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSStringKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSStringKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsThisType.cpp b/ets2panda/ir/ts/tsThisType.cpp index da5e36ad8ce7686708745112bd1cfb2cdf70101f..9af97be93c8b9f01a491a356b0e06e153cc7b6ec 100644 --- a/ets2panda/ir/ts/tsThisType.cpp +++ b/ets2panda/ir/ts/tsThisType.cpp @@ -24,12 +24,7 @@ namespace ark::es2panda::ir { void TSThisType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSThisType::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTupleType.cpp b/ets2panda/ir/ts/tsTupleType.cpp index cb69e8542ca30463bedbd2d1b2c1f4dab66f8bd2..d98cbd162299827eb3f569f9e88ad891da90f6aa 100644 --- a/ets2panda/ir/ts/tsTupleType.cpp +++ b/ets2panda/ir/ts/tsTupleType.cpp @@ -35,12 +35,8 @@ void TSTupleType::TransformChildren(const NodeTransformer &cb, std::string_view it = static_cast(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTupleType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp b/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp index da15ceaa4f1d0a0b9407dd8bdc7f5c889a0da728..c5b87201976b224ebaa86431ae451dd9c3a4dacc 100644 --- a/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp +++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp @@ -27,31 +27,44 @@ #include "ir/ts/tsTypeParameterDeclaration.h" namespace ark::es2panda::ir { + +SETTER_FOR_CHILD(TSTypeAliasDeclaration, TypeParameters, typeParams_, TSTypeParameterDeclaration *); +SETTER_FOR_CHILD(TSTypeAliasDeclaration, Id, id_, Identifier *); + +SETTER_FOR_ARENAVECTOR_CHILD(TSTypeAliasDeclaration, Annotations, annotations_, AnnotationUsage *); +SETTER_FOR_ARENAVECTOR_CHILD(TSTypeAliasDeclaration, Decorators, decorators_, Decorator *); + +SETTER_FOR_ARENAVECTOR_FIELD(TSTypeAliasDeclaration, TypeParamterTypes, typeParamTypes_, checker::Type *); + void TSTypeAliasDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(decorators_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsDecorator(); + auto const &decorators = Decorators(); + for (size_t ix = 0; ix < decorators.size(); ix++) { + if (auto *transformedNode = cb(decorators[ix]); decorators[ix] != transformedNode) { + decorators[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueDecorators(transformedNode->AsDecorator(), ix); } } - for (auto *&it : Annotations()) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); + auto const &annotations = Annotations(); + for (size_t ix = 0; ix < annotations.size(); ix++) { + if (auto *transformedNode = cb(annotations[ix]); annotations[ix] != transformedNode) { + annotations[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueAnnotations(transformedNode->AsAnnotationUsage(), ix); } } - if (auto *transformedNode = cb(id_); id_ != transformedNode) { - id_->SetTransformedNode(transformationName, transformedNode); - id_ = transformedNode->AsIdentifier(); + auto const id = Id(); + if (auto *transformedNode = cb(id); id != transformedNode) { + id->SetTransformedNode(transformationName, transformedNode); + SetId(transformedNode->AsIdentifier()); } - if (typeParams_ != nullptr) { - if (auto *transformedNode = cb(typeParams_); typeParams_ != transformedNode) { - typeParams_->SetTransformedNode(transformationName, transformedNode); - typeParams_ = transformedNode->AsTSTypeParameterDeclaration(); + auto const typeParams = TypeParams(); + if (typeParams != nullptr) { + if (auto *transformedNode = cb(typeParams); typeParams != transformedNode) { + typeParams->SetTransformedNode(transformationName, transformedNode); + SetTypeParameters(transformedNode->AsTSTypeParameterDeclaration()); } } @@ -65,7 +78,7 @@ void TSTypeAliasDeclaration::TransformChildren(const NodeTransformer &cb, std::s void TSTypeAliasDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(decorators_)) { + for (auto *it : VectorIterationGuard(Decorators())) { cb(it); } @@ -73,10 +86,12 @@ void TSTypeAliasDeclaration::Iterate(const NodeTraverser &cb) const cb(it); } - cb(id_); + auto const id = GetHistoryNode()->AsTSTypeAliasDeclaration()->id_; + cb(id); - if (typeParams_ != nullptr) { - cb(typeParams_); + auto typeParams = GetHistoryNode()->AsTSTypeAliasDeclaration()->typeParams_; + if (typeParams != nullptr) { + cb(typeParams); } if (TypeAnnotation() != nullptr) { @@ -87,11 +102,11 @@ void TSTypeAliasDeclaration::Iterate(const NodeTraverser &cb) const void TSTypeAliasDeclaration::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "TSTypeAliasDeclaration"}, - {"decorators", AstDumper::Optional(decorators_)}, + {"decorators", AstDumper::Optional(Decorators())}, {"annotations", AstDumper::Optional(Annotations())}, - {"id", id_}, + {"id", Id()}, {"typeAnnotation", AstDumper::Optional(TypeAnnotation())}, - {"typeParameters", AstDumper::Optional(typeParams_)}}); + {"typeParameters", AstDumper::Optional(TypeParams())}}); } bool TSTypeAliasDeclaration::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const @@ -126,14 +141,15 @@ void TSTypeAliasDeclaration::Dump(ir::SrcDumper *dumper) const dumper->Add("export "); } dumper->Add("type "); - id_->Dump(dumper); - if (typeParams_ != nullptr) { + Id()->Dump(dumper); + auto const typeParams = TypeParams(); + if (typeParams != nullptr) { dumper->Add("<"); - typeParams_->Dump(dumper); + typeParams->Dump(dumper); dumper->Add(">"); } dumper->Add(" = "); - if (id_->IsAnnotatedExpression()) { + if (Id()->IsAnnotatedExpression()) { auto type = TypeAnnotation(); ES2PANDA_ASSERT(type); type->Dump(dumper); diff --git a/ets2panda/ir/ts/tsTypeAliasDeclaration.h b/ets2panda/ir/ts/tsTypeAliasDeclaration.h index 4d44e9002136b9ce83f5bfd5dd2a9a3140b80aee..052ae6b12bdcd5c97732559234489449d7c87950 100644 --- a/ets2panda/ir/ts/tsTypeAliasDeclaration.h +++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.h @@ -40,6 +40,7 @@ public: typeParams_(typeParams), typeParamTypes_(allocator->Adapter()) { + EnableHistory(); } explicit TSTypeAliasDeclaration(ArenaAllocator *allocator, Identifier *id) @@ -50,41 +51,36 @@ public: typeParams_(nullptr), typeParamTypes_(allocator->Adapter()) { + EnableHistory(); } Identifier *Id() { - return id_; + RETURN_GET(TSTypeAliasDeclaration, id_); } const Identifier *Id() const { - return id_; + RETURN_GET(TSTypeAliasDeclaration, id_); } TSTypeParameterDeclaration *TypeParams() const { - return typeParams_; + RETURN_GET(TSTypeAliasDeclaration, typeParams_); } const ArenaVector &Decorators() const { - return decorators_; + RETURN_GET(TSTypeAliasDeclaration, decorators_); } - const ArenaVector *DecoratorsPtr() const override - { - return &Decorators(); - } - - void SetTypeParameters(ir::TSTypeParameterDeclaration *typeParams) - { - typeParams_ = typeParams; - } + void SetTypeParameters(ir::TSTypeParameterDeclaration *source); void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { - decorators_ = std::move(decorators); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + newNode->decorators_ = std::move(decorators); } bool CanHaveDecorator([[maybe_unused]] bool inTs) const override @@ -94,28 +90,29 @@ public: void SetTypeParameterTypes(ArenaVector &&typeParamTypes) { - typeParamTypes_ = std::move(typeParamTypes); + auto newNode = reinterpret_cast(GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + newNode->typeParamTypes_ = std::move(typeParamTypes); } ArenaVector const &TypeParameterTypes() const { - return typeParamTypes_; + RETURN_GET(TSTypeAliasDeclaration, typeParamTypes_); } - [[nodiscard]] ArenaVector &Annotations() noexcept - { - return annotations_; - } + [[nodiscard]] ArenaVector &Annotations(); [[nodiscard]] const ArenaVector &Annotations() const noexcept { - return annotations_; + RETURN_GET(TSTypeAliasDeclaration, annotations_); } void SetAnnotations(ArenaVector &&annotations) { - annotations_ = std::move(annotations); - for (AnnotationUsage *anno : annotations_) { + auto newNode = reinterpret_cast(GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + newNode->annotations_ = std::move(annotations); + for (AnnotationUsage *anno : newNode->annotations_) { anno->SetParent(this); } } @@ -137,15 +134,31 @@ public: void CleanUp() override { AstNode::CleanUp(); - typeParamTypes_.clear(); + ClearTypeParamterTypes(); } TSTypeAliasDeclaration *Construct(ArenaAllocator *allocator) override; void CopyTo(AstNode *other) const override; + void EmplaceAnnotations(AnnotationUsage *source); + void ClearAnnotations(); + void SetValueAnnotations(AnnotationUsage *source, size_t index); + + void EmplaceTypeParamterTypes(checker::Type *source); + void ClearTypeParamterTypes(); + void SetValueTypeParamterTypes(checker::Type *source, size_t index); + [[nodiscard]] ArenaVector &TypeParamterTypes(); + + void EmplaceDecorators(Decorator *source); + void ClearDecorators(); + void SetValueDecorators(Decorator *source, size_t index); + [[nodiscard]] ArenaVector &Decorators(); + private: bool RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const; friend class SizeOfNodeTest; + + void SetId(Identifier *source); ArenaVector decorators_; ArenaVector annotations_; Identifier *id_; diff --git a/ets2panda/ir/ts/tsTypeLiteral.cpp b/ets2panda/ir/ts/tsTypeLiteral.cpp index 418d5aa34da584c298c5e23a46dd7466dff7af61..d13f7662cdbe610180fa9735b0f2f7fc4b03e09e 100644 --- a/ets2panda/ir/ts/tsTypeLiteral.cpp +++ b/ets2panda/ir/ts/tsTypeLiteral.cpp @@ -34,12 +34,8 @@ void TSTypeLiteral::TransformChildren(const NodeTransformer &cb, std::string_vie it = transformedNode; } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTypeLiteral::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTypeOperator.cpp b/ets2panda/ir/ts/tsTypeOperator.cpp index 7e66c028434fe001fbb0cafa93a7ca9d59bc2b0e..2fa2ad26adb615ba84351e83fc4004db8bf77aed 100644 --- a/ets2panda/ir/ts/tsTypeOperator.cpp +++ b/ets2panda/ir/ts/tsTypeOperator.cpp @@ -28,12 +28,8 @@ void TSTypeOperator::TransformChildren(const NodeTransformer &cb, std::string_vi type_->SetTransformedNode(transformationName, transformedNode); type_ = static_cast(transformedNode); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTypeOperator::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTypeParameter.cpp b/ets2panda/ir/ts/tsTypeParameter.cpp index 88d4b0885510fce70ecd42d08eabccb1cf55d1bd..5405a42fa1594ce56d15b2f52986ccf47a4e05e4 100644 --- a/ets2panda/ir/ts/tsTypeParameter.cpp +++ b/ets2panda/ir/ts/tsTypeParameter.cpp @@ -25,44 +25,57 @@ #include "utils/arena_containers.h" namespace ark::es2panda::ir { + +SETTER_FOR_CHILD(TSTypeParameter, Constraint, constraint_, TypeNode *); +SETTER_FOR_CHILD(TSTypeParameter, DefaultType, defaultType_, TypeNode *); +SETTER_FOR_CHILD(TSTypeParameter, Name, name_, Identifier *); + void TSTypeParameter::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - if (auto *transformedNode = cb(name_); name_ != transformedNode) { - name_->SetTransformedNode(transformationName, transformedNode); - name_ = transformedNode->AsIdentifier(); + auto const name = Name(); + if (auto *transformedNode = cb(name); name != transformedNode) { + name->SetTransformedNode(transformationName, transformedNode); + SetName(transformedNode->AsIdentifier()); } - if (constraint_ != nullptr) { - if (auto *transformedNode = cb(constraint_); constraint_ != transformedNode) { - constraint_->SetTransformedNode(transformationName, transformedNode); - constraint_ = static_cast(transformedNode); + auto const constraint = Constraint(); + if (constraint != nullptr) { + if (auto *transformedNode = cb(constraint); constraint != transformedNode) { + constraint->SetTransformedNode(transformationName, transformedNode); + SetConstraint(static_cast(transformedNode)); } } - if (defaultType_ != nullptr) { - if (auto *transformedNode = cb(defaultType_); defaultType_ != transformedNode) { - defaultType_->SetTransformedNode(transformationName, transformedNode); - defaultType_ = static_cast(transformedNode); + auto const defaultType = DefaultType(); + if (defaultType != nullptr) { + if (auto *transformedNode = cb(defaultType); defaultType != transformedNode) { + defaultType->SetTransformedNode(transformationName, transformedNode); + SetDefaultType(static_cast(transformedNode)); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); + + auto const annotations = Annotations(); + for (size_t ix = 0; ix < annotations.size(); ix++) { + if (auto *transformedNode = cb(annotations[ix]); annotations[ix] != transformedNode) { + annotations[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueAnnotations(transformedNode->AsAnnotationUsage(), ix); } } } void TSTypeParameter::Iterate(const NodeTraverser &cb) const { - cb(name_); + auto const name = GetHistoryNodeAs()->name_; + cb(name); - if (constraint_ != nullptr) { - cb(constraint_); + auto const constraint = GetHistoryNodeAs()->constraint_; + if (constraint != nullptr) { + cb(constraint); } - if (defaultType_ != nullptr) { - cb(defaultType_); + auto const defaultType = GetHistoryNodeAs()->defaultType_; + if (defaultType != nullptr) { + cb(defaultType); } for (auto *it : VectorIterationGuard(Annotations())) { cb(it); @@ -72,9 +85,9 @@ void TSTypeParameter::Iterate(const NodeTraverser &cb) const void TSTypeParameter::Dump(ir::AstDumper *dumper) const { dumper->Add({{"type", "TSTypeParameter"}, - {"name", name_}, - {"constraint", AstDumper::Optional(constraint_)}, - {"default", AstDumper::Optional(defaultType_)}, + {"name", Name()}, + {"constraint", AstDumper::Optional(Constraint())}, + {"default", AstDumper::Optional(DefaultType())}, {"in", AstDumper::Optional(IsIn())}, {"out", AstDumper::Optional(IsOut())}, {"annotations", AstDumper::Optional(Annotations())}}); @@ -92,15 +105,15 @@ void TSTypeParameter::Dump(ir::SrcDumper *dumper) const dumper->Add("out "); } - name_->Dump(dumper); + Name()->Dump(dumper); - if (defaultType_ != nullptr) { + if (DefaultType() != nullptr) { dumper->Add(" = "); - defaultType_->Dump(dumper); + DefaultType()->Dump(dumper); } - if (constraint_ != nullptr) { + if (Constraint() != nullptr) { dumper->Add(" extends "); - constraint_->Dump(dumper); + Constraint()->Dump(dumper); } } diff --git a/ets2panda/ir/ts/tsTypeParameter.h b/ets2panda/ir/ts/tsTypeParameter.h index fff183fc3c427f2e172728b8c058dd01cd71036e..1bc9b8c25fc0431e334292980ce2ff8489d5c301 100644 --- a/ets2panda/ir/ts/tsTypeParameter.h +++ b/ets2panda/ir/ts/tsTypeParameter.h @@ -31,6 +31,7 @@ public: constraint_(constraint), defaultType_(defaultType) { + EnableHistory(); } explicit TSTypeParameter(Identifier *name, TypeNode *constraint, TypeNode *defaultType, ModifierFlags flags, @@ -41,42 +42,66 @@ public: defaultType_(defaultType) { ES2PANDA_ASSERT(flags == ModifierFlags::NONE || flags == ModifierFlags::IN || flags == ModifierFlags::OUT); + EnableHistory(); + } + + explicit TSTypeParameter(Identifier *name, TypeNode *constraint, TypeNode *defaultType, ModifierFlags flags, + ArenaAllocator *const allocator, AstNodeHistory *history) + : AnnotationAllowed(AstNodeType::TS_TYPE_PARAMETER, flags, allocator), + name_(name), + constraint_(constraint), + defaultType_(defaultType) + { + ES2PANDA_ASSERT(flags == ModifierFlags::NONE || flags == ModifierFlags::IN || flags == ModifierFlags::OUT); + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } + } + + explicit TSTypeParameter(Identifier *name, TypeNode *constraint, TypeNode *defaultType, + ArenaAllocator *const allocator, AstNodeHistory *history) + : AnnotationAllowed(AstNodeType::TS_TYPE_PARAMETER, allocator), + name_(name), + constraint_(constraint), + defaultType_(defaultType) + { + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } const Identifier *Name() const { - return name_; + RETURN_GET(TSTypeParameter, name_); } Identifier *Name() { - return name_; + RETURN_GET(TSTypeParameter, name_); } TypeNode *Constraint() { - return constraint_; + RETURN_GET(TSTypeParameter, constraint_); } const TypeNode *Constraint() const { - return constraint_; + RETURN_GET(TSTypeParameter, constraint_); } - void SetConstraint(TypeNode *constraint) - { - constraint_ = constraint; - } + void SetConstraint(TypeNode *source); TypeNode *DefaultType() const { - return defaultType_; + RETURN_GET(TSTypeParameter, defaultType_); } - void SetDefaultType(TypeNode *defaultType) - { - defaultType_ = defaultType; - } + void SetDefaultType(TypeNode *source); void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; void Iterate(const NodeTraverser &cb) const override; @@ -97,6 +122,8 @@ public: private: friend class SizeOfNodeTest; + void SetName(Identifier *source); + Identifier *name_; TypeNode *constraint_; TypeNode *defaultType_; diff --git a/ets2panda/ir/ts/tsTypeParameterDeclaration.cpp b/ets2panda/ir/ts/tsTypeParameterDeclaration.cpp index a236ed060c7ce2f83bb27d40e2bea133e6df6d18..bf6d85b828a71029ee8ef181429a1ca559569736 100644 --- a/ets2panda/ir/ts/tsTypeParameterDeclaration.cpp +++ b/ets2panda/ir/ts/tsTypeParameterDeclaration.cpp @@ -23,33 +23,38 @@ #include "ir/ts/tsTypeParameter.h" namespace ark::es2panda::ir { + +SETTER_FOR_FIELD(TSTypeParameterDeclaration, Scope, scope_, varbinder::LocalScope *); +SETTER_FOR_FIELD(TSTypeParameterDeclaration, RequiredParams, requiredParams_, size_t); + void TSTypeParameterDeclaration::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) { - for (auto *&it : VectorIterationGuard(params_)) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsTSTypeParameter(); + auto const params = Params(); + for (size_t ix = 0; ix < params.size(); ix++) { + if (auto *transformedNode = cb(params[ix]); params[ix] != transformedNode) { + params[ix]->SetTransformedNode(transformationName, transformedNode); + SetValueParams(transformedNode->AsTSTypeParameter(), ix); } } } void TSTypeParameterDeclaration::Iterate(const NodeTraverser &cb) const { - for (auto *it : VectorIterationGuard(params_)) { + for (auto *it : VectorIterationGuard(Params())) { cb(it); } } void TSTypeParameterDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "TSTypeParameterDeclaration"}, {"params", params_}}); + dumper->Add({{"type", "TSTypeParameterDeclaration"}, {"params", Params()}}); } void TSTypeParameterDeclaration::Dump(ir::SrcDumper *dumper) const { - for (auto param : params_) { + for (auto param : Params()) { param->Dump(dumper); - if (param != params_.back()) { + if (param != Params().back()) { dumper->Add(", "); } } diff --git a/ets2panda/ir/ts/tsTypeParameterDeclaration.h b/ets2panda/ir/ts/tsTypeParameterDeclaration.h index 9fef5c44ff68afe9316bdd7b1242cdb37350463d..f1b37dfe6ab91103190313f6ebcac73d981bc249 100644 --- a/ets2panda/ir/ts/tsTypeParameterDeclaration.h +++ b/ets2panda/ir/ts/tsTypeParameterDeclaration.h @@ -29,6 +29,20 @@ public: params_(std::move(params)), requiredParams_(requiredParams) { + EnableHistory(); + } + + explicit TSTypeParameterDeclaration(ArenaVector &¶ms, size_t requiredParams, + AstNodeHistory *history) + : Expression(AstNodeType::TS_TYPE_PARAMETER_DECLARATION), + params_(std::move(params)), + requiredParams_(requiredParams) + { + if (history != nullptr) { + history_ = history; + } else { + EnableHistory(); + } } [[nodiscard]] bool IsScopeBearer() const noexcept override @@ -38,35 +52,43 @@ public: [[nodiscard]] varbinder::LocalScope *Scope() const noexcept override { - return scope_; + RETURN_GET(TSTypeParameterDeclaration, scope_); } - void SetScope(varbinder::LocalScope *scope) - { - scope_ = scope; - } + void SetScope(varbinder::LocalScope *source); void ClearScope() noexcept override { - scope_ = nullptr; + SetScope(nullptr); } const ArenaVector &Params() const { - return params_; + RETURN_GET(TSTypeParameterDeclaration, params_); } void AddParam(TSTypeParameter *param) { - if (requiredParams_ == params_.size() && param->DefaultType() == nullptr) { - requiredParams_++; + if (RequiredParams() == Params().size() && param->DefaultType() == nullptr) { + SetRequiredParams(RequiredParams() + 1); } - params_.push_back(param); + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + newNode->params_.emplace_back(param); + } + + void SetValueParams(TSTypeParameter *source, size_t index) + { + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); + CHANGEABLE_SET_CHILD(newNode); + auto &arenaVector = newNode->params_; + ES2PANDA_ASSERT(arenaVector.size() > index); + arenaVector[index] = source; } size_t RequiredParams() const { - return requiredParams_; + RETURN_GET(TSTypeParameterDeclaration, requiredParams_); } void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -88,6 +110,9 @@ public: private: friend class SizeOfNodeTest; + + void SetRequiredParams(size_t source); + ArenaVector params_; varbinder::LocalScope *scope_ {nullptr}; size_t requiredParams_; diff --git a/ets2panda/ir/ts/tsTypePredicate.cpp b/ets2panda/ir/ts/tsTypePredicate.cpp index a1b253d850f2e1d375e3d5f7e0cd3b6c4d08d4b0..0ab2158429af2721d494a5d637138a376c662d11 100644 --- a/ets2panda/ir/ts/tsTypePredicate.cpp +++ b/ets2panda/ir/ts/tsTypePredicate.cpp @@ -37,12 +37,8 @@ void TSTypePredicate::TransformChildren(const NodeTransformer &cb, std::string_v typeAnnotation_ = static_cast(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTypePredicate::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTypeQuery.cpp b/ets2panda/ir/ts/tsTypeQuery.cpp index 70fe7b63fc1e824121bc6d291b74e10ea3954e9f..5fa24495e892a371b09abc180c525b490e16b252 100644 --- a/ets2panda/ir/ts/tsTypeQuery.cpp +++ b/ets2panda/ir/ts/tsTypeQuery.cpp @@ -29,12 +29,8 @@ void TSTypeQuery::TransformChildren(const NodeTransformer &cb, std::string_view exprName_->SetTransformedNode(transformationName, transformedNode); exprName_ = transformedNode->AsExpression(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTypeQuery::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsTypeReference.cpp b/ets2panda/ir/ts/tsTypeReference.cpp index 459789b7185b1300ff68c8d9c3d2fa6feab061a8..57b8f7d2ae2cd662db0504c73723e943cb43585f 100644 --- a/ets2panda/ir/ts/tsTypeReference.cpp +++ b/ets2panda/ir/ts/tsTypeReference.cpp @@ -44,12 +44,8 @@ void TSTypeReference::TransformChildren(const NodeTransformer &cb, std::string_v typeName_->SetTransformedNode(transformationName, transformedNode); typeName_ = transformedNode->AsExpression(); } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSTypeReference::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsUndefinedKeyword.cpp b/ets2panda/ir/ts/tsUndefinedKeyword.cpp index 4070aaf0b20e9b8a6141702387b01c7c84fe3579..5053cebca07ecfc83a830d9cda91a4cb815e34ad 100644 --- a/ets2panda/ir/ts/tsUndefinedKeyword.cpp +++ b/ets2panda/ir/ts/tsUndefinedKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSUndefinedKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSUndefinedKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsUnionType.cpp b/ets2panda/ir/ts/tsUnionType.cpp index a25ccceccb5ce236864d0f7d524778426a254f31..aca8a8aa8995d717e562b865296923db544b551e 100644 --- a/ets2panda/ir/ts/tsUnionType.cpp +++ b/ets2panda/ir/ts/tsUnionType.cpp @@ -30,12 +30,8 @@ void TSUnionType::TransformChildren(const NodeTransformer &cb, std::string_view it = static_cast(transformedNode); } } - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + + TransformAnnotations(cb, transformationName); } void TSUnionType::Iterate(const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsUnknownKeyword.cpp b/ets2panda/ir/ts/tsUnknownKeyword.cpp index f1daafebdc22bbb772af9ba4168b78c37c2886d9..dd0bc5e848c6dff5ce17822b2eddad1c5d6ee49c 100644 --- a/ets2panda/ir/ts/tsUnknownKeyword.cpp +++ b/ets2panda/ir/ts/tsUnknownKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSUnknownKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSUnknownKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/ts/tsVoidKeyword.cpp b/ets2panda/ir/ts/tsVoidKeyword.cpp index d5a4341f2c29273020f642963379208472917898..ff09cc56d86b65be9f42072b644186486fbf5a7c 100644 --- a/ets2panda/ir/ts/tsVoidKeyword.cpp +++ b/ets2panda/ir/ts/tsVoidKeyword.cpp @@ -25,12 +25,7 @@ namespace ark::es2panda::ir { void TSVoidKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, [[maybe_unused]] std::string_view const transformationName) { - for (auto *&it : VectorIterationGuard(Annotations())) { - if (auto *transformedNode = cb(it); it != transformedNode) { - it->SetTransformedNode(transformationName, transformedNode); - it = transformedNode->AsAnnotationUsage(); - } - } + TransformAnnotations(cb, transformationName); } void TSVoidKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const diff --git a/ets2panda/ir/typed.h b/ets2panda/ir/typed.h index 0c3f32f3ee4f6799cf522b40cb4248b905a1960f..939a659c456480d630205da33475281463da33e1 100644 --- a/ets2panda/ir/typed.h +++ b/ets2panda/ir/typed.h @@ -38,17 +38,25 @@ public: [[nodiscard]] checker::Type const *TsType() const { - return tsType_; + return AstNode::GetHistoryNodeAs>()->tsType_; } [[nodiscard]] checker::Type *TsType() { - return tsType_; + return AstNode::GetHistoryNodeAs>()->tsType_; } checker::Type *SetTsType(checker::Type *tsType) noexcept { - return (tsType_ = tsType); + auto nowNode = AstNode::GetHistoryNodeAs>(); + if (nowNode->tsType_ != tsType) { + if (InCheckerPhase() && nowNode->tsType_ == nullptr) { + nowNode->tsType_ = tsType; + }else { + AstNode::GetOrCreateHistoryNodeAs>()->tsType_ = tsType; + } + } + return tsType; } bool IsTyped() const override diff --git a/ets2panda/lexer/token/sourceLocation.h b/ets2panda/lexer/token/sourceLocation.h index a150a8cfb08cebc09bff2457f506559a42776780..b6557e4d6320509ddfce93860c717d38ec5a289e 100644 --- a/ets2panda/lexer/token/sourceLocation.h +++ b/ets2panda/lexer/token/sourceLocation.h @@ -52,6 +52,11 @@ public: const parser::Program *Program() const; + bool operator!=(const SourcePosition &other) const + { + return index != other.index || line != other.line || program_ != other.program_; + } + private: const parser::Program *program_ {}; }; @@ -68,6 +73,11 @@ public: SourcePosition start {}; SourcePosition end {}; // NOLINTEND(misc-non-private-member-variables-in-classes) + + bool operator!=(const SourceRange &other) const + { + return start != other.start || end != other.end; + } }; class SourceLocation { diff --git a/ets2panda/lsp/src/rename.cpp b/ets2panda/lsp/src/rename.cpp index 453703e9411882cc0e94d47c5bb8147147d6f4f8..3c7c0441fd63ecd26ab74a84ba2f883b6b06b637 100644 --- a/ets2panda/lsp/src/rename.cpp +++ b/ets2panda/lsp/src/rename.cpp @@ -31,7 +31,7 @@ constexpr size_t QUOTE_START_OFFSET = 1; RenameInfoType GetRenameInfo(es2panda_Context *context, size_t pos) { auto ctx = reinterpret_cast(context); - auto checker = reinterpret_cast(ctx)->checker->AsETSChecker(); + auto checker = reinterpret_cast(ctx)->GetChecker()->AsETSChecker(); auto program = reinterpret_cast(ctx)->parserProgram; auto node = GetAdjustedLocation(GetTouchingPropertyName(context, pos), true, ctx->allocator); if (node.has_value() && NodeIsEligibleForRename(node.value())) { diff --git a/ets2panda/parser/ETSFormattedParser.cpp b/ets2panda/parser/ETSFormattedParser.cpp index 93fac4b3e5590269a1692b433c089510359e52bc..d0b01fdad556ca202f89738c1de968e4313372a7 100644 --- a/ets2panda/parser/ETSFormattedParser.cpp +++ b/ets2panda/parser/ETSFormattedParser.cpp @@ -374,7 +374,7 @@ ArenaVector ETSParser::CreateFormattedStatements(std::string_vi ir::AstNode *ETSParser::CreateFormattedClassFieldDefinition(std::string_view sourceCode, std::vector &insertingNodes) { - static ArenaVector const DUMMY_ARRAY {Allocator()->Adapter()}; + thread_local static ArenaVector const DUMMY_ARRAY {Allocator()->Adapter()}; insertingNodes_.swap(insertingNodes); auto *const property = CreateClassElement(sourceCode, DUMMY_ARRAY, ir::ClassDefinitionModifiers::NONE); @@ -390,7 +390,7 @@ ir::AstNode *ETSParser::CreateFormattedClassFieldDefinition(std::string_view sou ir::AstNode *ETSParser::CreateFormattedClassMethodDefinition(std::string_view sourceCode, std::vector &insertingNodes) { - static ArenaVector const DUMMY_ARRAY {Allocator()->Adapter()}; + thread_local static ArenaVector const DUMMY_ARRAY {Allocator()->Adapter()}; insertingNodes_.swap(insertingNodes); auto *const property = CreateClassElement(sourceCode, DUMMY_ARRAY, ir::ClassDefinitionModifiers::NONE); diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index bcf77bd1baf73f8ed046f7599428bf1256000e27..9b8603121df0dec5500321e519708f5334d750a8 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -71,6 +71,7 @@ #include "ir/ts/tsThisType.h" #include "generated/signatures.h" #include "generated/diagnostic.h" +#include "public/public.h" namespace ark::es2panda::parser { class FunctionContext; @@ -131,7 +132,7 @@ void ETSParser::ParseProgram(ScriptKind kind) if ((GetContext().Status() & parser::ParserStatus::DEPENDENCY_ANALYZER_MODE) == 0) { script = ParseETSGlobalScript(startLoc, statements); } else { - script = ParseImportsOnly(startLoc, statements); + script = ParseImportsAndReExportOnly(startLoc, statements); } if ((GetContext().Status() & ParserStatus::IN_PACKAGE) != 0) { @@ -161,7 +162,8 @@ ir::ETSModule *ETSParser::ParseETSGlobalScript(lexer::SourcePosition startLoc, A return etsModule; } -ir::ETSModule *ETSParser::ParseImportsOnly(lexer::SourcePosition startLoc, ArenaVector &statements) +ir::ETSModule *ETSParser::ParseImportsAndReExportOnly(lexer::SourcePosition startLoc, + ArenaVector &statements) { ETSNolintParser etsnolintParser(this); etsnolintParser.CollectETSNolints(); @@ -208,7 +210,23 @@ ArenaVector ETSParser::ParseDefaultSources(std::stri auto statements = ParseImportDeclarations(); GetContext().Status() &= ~ParserStatus::IN_DEFAULT_IMPORTS; - AddExternalSource(ParseSources()); + static bool ekko = false; + if (!Context()->compiledByCapi) { + if (ekko) { + return statements; + } else { + ekko = true; + AddExternalSource(ParseSources()); + } + } else { + if (Context()->globalContext != nullptr && Context()->globalContext->stdLibAstCache != nullptr) { + globalProgram_->MergeExternalSource(Context()->globalContext->stdLibAstCache); + importPathManager_->ClearParseList(); + } else { + ekko = true; + AddExternalSource(ParseSources()); + } + } return statements; } @@ -279,6 +297,19 @@ std::vector ETSParser::ParseSources(bool firstSource) if (parseList[idx].isParsed) { continue; } + + if (Context()->globalContext != nullptr) { + auto &importData = parseList[idx].importData; + auto src = importData.HasSpecifiedDeclPath() ? importData.declPath : importData.resolvedSource; + const auto &absPath = std::string {util::Path {src, Allocator()}.GetAbsolutePath()}; + auto cacheExtProgs = Context()->globalContext->cachedExternalPrograms; + if (cacheExtProgs.find(absPath) != cacheExtProgs.end() && cacheExtProgs[absPath] != nullptr) { + globalProgram_->MergeExternalSource(cacheExtProgs[absPath]); + importPathManager_->MarkAsParsed(parseList[idx].importData.resolvedSource); + continue; + } + } + const auto &data = parseList[idx].importData; if (data.declPath.empty()) { importPathManager_->MarkAsParsed(data.resolvedSource); diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index aaffaa3d8b7af91525d3d0ef0bce2f069fa66372..f3a25eaf799534da4fd5ad72664cfcd59b33ce05 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -328,7 +328,8 @@ private: ir::ImportKinds importKind); parser::Program *ParseSource(const SourceFile &sourceFile); ir::ETSModule *ParseETSGlobalScript(lexer::SourcePosition startLoc, ArenaVector &statements); - ir::ETSModule *ParseImportsOnly(lexer::SourcePosition startLoc, ArenaVector &statements); + ir::ETSModule *ParseImportsAndReExportOnly(lexer::SourcePosition startLoc, + ArenaVector &statements); ir::AstNode *ParseImportDefaultSpecifier(ArenaVector *specifiers) override; void *ApplyAnnotationsToClassElement(ir::AstNode *property, ArenaVector &&annotations, diff --git a/ets2panda/parser/ETSparserNamespaces.cpp b/ets2panda/parser/ETSparserNamespaces.cpp index ea4a8feb4bad30cdaf3ca8bfcbcf73f4ac6995d2..50240599974741629a8b0ec7b6ceb6b993125256 100644 --- a/ets2panda/parser/ETSparserNamespaces.cpp +++ b/ets2panda/parser/ETSparserNamespaces.cpp @@ -82,7 +82,7 @@ ir::ETSModule *ETSParser::ParseNamespaceImp(ir::ModifierFlags flags) if ((flags & ir::ModifierFlags::DECLARE) != 0) { child->AddModifier(ir::ModifierFlags::DECLARE); } - parent->Statements().emplace_back(child); + parent->AddStatement(child); parent = child; } ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE); diff --git a/ets2panda/parser/ETSparserTypes.cpp b/ets2panda/parser/ETSparserTypes.cpp index 7c247dcb73f4ec2783f47f50decaf280bcb13168..28144a3d76cb61e1bb9f82a3832a1e3fd1d9ef0f 100644 --- a/ets2panda/parser/ETSparserTypes.cpp +++ b/ets2panda/parser/ETSparserTypes.cpp @@ -391,7 +391,7 @@ std::pair ETSParser::GetTypeAnnotationFromParentheses(Type return std::make_pair(typeAnnotation, true); } -static bool IsSimpleReturnThis(lexer::Token const &tokenAfterThis) +bool IsSimpleReturnThis(lexer::Token const &tokenAfterThis) { return (tokenAfterThis.Type() == lexer::TokenType::PUNCTUATOR_ARROW) || (tokenAfterThis.Type() == lexer::TokenType::PUNCTUATOR_COMMA) || diff --git a/ets2panda/parser/parserImpl.h b/ets2panda/parser/parserImpl.h index d64de90591844ae65634a889dd50971c16c1b197..c71ad06628d3c17756b408eace5e79973cf7e316 100644 --- a/ets2panda/parser/parserImpl.h +++ b/ets2panda/parser/parserImpl.h @@ -37,6 +37,10 @@ class Options; class SourcePositionHelper; } // namespace ark::es2panda::util +namespace ark::es2panda::public_lib { +struct Context; +} // namespace ark::es2panda::public_lib + namespace ark::es2panda::parser { using ENUMBITOPS_OPERATORS; @@ -101,6 +105,16 @@ public: lexer::SourcePosition GetPositionForDiagnostic() const; + void SetContext(public_lib::Context *ctx) + { + ctx_ = ctx; + } + + public_lib::Context *Context() + { + return ctx_; + } + protected: virtual void ParseProgram(ScriptKind kind); static ExpressionParseFlags CarryExpressionParserFlag(ExpressionParseFlags origin, ExpressionParseFlags carry); @@ -569,6 +583,7 @@ private: lexer::Lexer *lexer_ {}; const util::Options *options_; util::DiagnosticEngine &diagnosticEngine_; + public_lib::Context *ctx_ {nullptr}; }; } // namespace ark::es2panda::parser diff --git a/ets2panda/parser/program/program.cpp b/ets2panda/parser/program/program.cpp index cd4ef559335f29546def94def9687fae01b755d2..a3a7537212ff5c79547bf7145a33fbae52e43d84 100644 --- a/ets2panda/parser/program/program.cpp +++ b/ets2panda/parser/program/program.cpp @@ -22,18 +22,67 @@ #include "ir/astDump.h" #include "ir/base/classDefinition.h" #include "ir/statements/blockStatement.h" +// #include "ir/ets/etsModule.h" + +#include namespace ark::es2panda::parser { Program::Program(ArenaAllocator *allocator, varbinder::VarBinder *varbinder) : allocator_(allocator), - varbinder_(varbinder), externalSources_(allocator_->Adapter()), directExternalSources_(allocator_->Adapter()), extension_(varbinder->Extension()), etsnolintCollection_(allocator_->Adapter()), - cfg_(allocator_->New(allocator_)) + cfg_(allocator_->New(allocator_)), + declGenExportNodes_(allocator_->Adapter()) +{ + PushVarBinder(varbinder); +} + +void Program::PushVarBinder(varbinder::VarBinder *varbinder) { + varbinders_.insert({compiler::GetPhaseManager()->GetCurrentMajor(), varbinder}); +} + +void Program::PushVarBinder(int32_t major, varbinder::VarBinder *varbinder) +{ + varbinders_.insert({major, varbinder}); +} + +const varbinder::VarBinder *Program::VarBinder() const +{ + return varbinders_.at(compiler::GetPhaseManager()->GetCurrentMajor()); +} + +varbinder::VarBinder *Program::VarBinder() +{ + return varbinders_.at(compiler::GetPhaseManager()->GetCurrentMajor()); +} + +varbinder::VarBinder *Program::FirstVarBinder() +{ + return varbinders_.at(0); +} + +checker::Checker *Program::FirstChecker() +{ + return checkers_.front(); +} + +checker::Checker *Program::Checker() +{ + return checkers_.at(compiler::GetPhaseManager()->GetCurrentMajor()); +} + +void Program::PushChecker(checker::Checker *checker) +{ + checkers_.push_back(checker); +} + +const checker::Checker *Program::Checker() const +{ + return checkers_.at(compiler::GetPhaseManager()->GetCurrentMajor()); } std::string Program::Dump() const @@ -50,12 +99,12 @@ void Program::DumpSilent() const varbinder::ClassScope *Program::GlobalClassScope() { - return globalClass_->Scope()->AsClassScope(); + return GlobalClass()->Scope()->AsClassScope(); } const varbinder::ClassScope *Program::GlobalClassScope() const { - return globalClass_->Scope()->AsClassScope(); + return GlobalClass()->Scope()->AsClassScope(); } varbinder::GlobalScope *Program::GlobalScope() @@ -124,9 +173,31 @@ compiler::CFG *Program::GetCFG() return cfg_; } +ir::ClassDefinition *Program::GlobalClass() +{ + return ast_->AsETSModule()->GlobalClass(); +} + +const ir::ClassDefinition *Program::GlobalClass() const +{ + return ast_->AsETSModule()->GlobalClass(); +} + +void Program::SetGlobalClass(ir::ClassDefinition *globalClass) +{ + ast_->AsETSModule()->SetGlobalClass(globalClass); +} + const compiler::CFG *Program::GetCFG() const { return cfg_; } +void Program::MergeExternalSource(const ExternalSource *externalSource) +{ + for (const auto &[moduleName, extProgs] : *externalSource) { + externalSources_.emplace(moduleName, extProgs); + } +} + } // namespace ark::es2panda::parser diff --git a/ets2panda/parser/program/program.h b/ets2panda/parser/program/program.h index 7820ed68132b23ce73627d5e24e472fe36e8fd5b..7dbab3596a4854d43dbbd94f497e8037634dc013 100644 --- a/ets2panda/parser/program/program.h +++ b/ets2panda/parser/program/program.h @@ -26,6 +26,7 @@ #include #include +#include namespace ark::es2panda::ir { class BlockStatement; @@ -39,6 +40,10 @@ namespace ark::es2panda::compiler { class CFG; } // namespace ark::es2panda::compiler +namespace ark::es2panda::checker { +class Checker; +} // namespace ark::es2panda::checker + namespace ark::es2panda::parser { enum class ScriptKind { SCRIPT, MODULE, STDLIB }; enum EntityType { CLASS_PROPERTY = 0, METHOD_DEFINITION = 1, CLASS_DEFINITION = 2, TS_INTERFACE_DECLARATION = 3 }; @@ -74,15 +79,22 @@ public: return allocator_; } - const varbinder::VarBinder *VarBinder() const - { - return varbinder_; - } + void PushVarBinder(varbinder::VarBinder *varbinder); - varbinder::VarBinder *VarBinder() - { - return varbinder_; - } + void PushVarBinder(int32_t major, varbinder::VarBinder *varbinder); + + const varbinder::VarBinder *VarBinder() const; + + varbinder::VarBinder *VarBinder(); + + varbinder::VarBinder *FirstVarBinder(); + + checker::Checker *FirstChecker(); + + checker::Checker *Checker(); + const checker::Checker *Checker() const; + + void PushChecker(checker::Checker *checker); ScriptExtension Extension() const { @@ -161,20 +173,11 @@ public: MaybeTransformToDeclarationModule(); } - ir::ClassDefinition *GlobalClass() - { - return globalClass_; - } + ir::ClassDefinition *GlobalClass(); - const ir::ClassDefinition *GlobalClass() const - { - return globalClass_; - } + const ir::ClassDefinition *GlobalClass() const; - void SetGlobalClass(ir::ClassDefinition *globalClass) - { - globalClass_ = globalClass; - } + void SetGlobalClass(ir::ClassDefinition *globalClass); ExternalSource &ExternalSources() { @@ -265,6 +268,16 @@ public: return isASTchecked_; } + void MarkASTAsLowered() + { + isASTlowered_ = true; + } + + bool IsASTLowered() const + { + return isASTlowered_; + } + bool IsStdLib() const { // NOTE (hurton): temporary solution, needs rework when std sources are renamed @@ -285,7 +298,7 @@ public: void AddNodeToETSNolintCollection(const ir::AstNode *node, const std::set &warningsCollection); bool NodeContainsETSNolint(const ir::AstNode *node, ETSWarnings warning); - std::vector> &DeclGenExportNodes() + ArenaUnorderedMap &DeclGenExportNodes() { // NOTE: ExportNodes is not supported now. return declGenExportNodes_; @@ -293,7 +306,8 @@ public: void AddDeclGenExportNode(const std::string &declGenExportStr, ir::AstNode *node) { - declGenExportNodes_.emplace_back(declGenExportStr, node); + auto key = util::UString(declGenExportStr, allocator_).View(); + declGenExportNodes_.emplace(key, node); } // The name "IsDied", because correct value of canary is a necessary condition for the life of "Program", but @@ -312,13 +326,36 @@ public: compiler::CFG *GetCFG(); const compiler::CFG *GetCFG() const; -private: void MaybeTransformToDeclarationModule(); + void MergeExternalSource(const ExternalSource *externalSource); + + std::map> GetFileDependencies() { + return fileDependencies_; + } + + std::map> GetFileDependants() { + return fileDependants_; + } + + void AddFileDependencies(std::string file, std::string depFile) { + if (!fileDependencies_.count(file)) { + fileDependencies_[file] = std::set(); + } + fileDependencies_[file].insert(depFile); + } + + void AddFileDependants(std::string file, std::string dependantFile) { + if (!fileDependants_.count(file)) { + fileDependants_[file] = std::set(); + } + fileDependants_[file].insert(dependantFile); + } + +private: ArenaAllocator *allocator_ {}; - varbinder::VarBinder *varbinder_ {}; ir::BlockStatement *ast_ {}; - ir::ClassDefinition *globalClass_ {}; + // ir::ClassDefinition *globalClass_ {}; util::StringView sourceCode_ {}; util::Path sourceFile_ {}; util::StringView sourceFileFolder_ {}; @@ -331,10 +368,14 @@ private: ETSNolintsCollectionMap etsnolintCollection_; util::ModuleInfo moduleInfo_; bool isASTchecked_ {}; + bool isASTlowered_ {}; lexer::SourcePosition packageStartPosition_ {}; compiler::CFG *cfg_; - std::vector> declGenExportNodes_; - + ArenaUnorderedMap declGenExportNodes_; + std::map> fileDependencies_; + std::map> fileDependants_; + std::map varbinders_ {}; + std::vector checkers_ {}; #ifndef NDEBUG const static uint32_t POISON_VALUE {0x12346789}; uint32_t poisonValue_ {POISON_VALUE}; diff --git a/ets2panda/public/cppToCTypes.yaml b/ets2panda/public/cppToCTypes.yaml index b46f46f021b3a077c000e9f70dab2db5343d1a48..0bdef32d02bc5eb3fa603468afac4a7b77efb4b8 100644 --- a/ets2panda/public/cppToCTypes.yaml +++ b/ets2panda/public/cppToCTypes.yaml @@ -1942,7 +1942,7 @@ change_types: max_ptr_depth: 1 new_args: cast: - expression: auto |es2panda_arg.type.ptr_depth||arg_name|E2p = reinterpret_cast(context)->checker; + expression: auto |es2panda_arg.type.ptr_depth||arg_name|E2p = reinterpret_cast(context)->GetChecker(); call_cast: start: >- (reinterpret_cast(context)->checker)-> @@ -1997,7 +1997,7 @@ change_types: new_args: cast: expression: >- - auto *|arg_name|E2p = reinterpret_cast(context)->checker->AsETSChecker(); + auto *|arg_name|E2p = reinterpret_cast(context)->GetChecker()->AsETSChecker(); call_cast: start: >- (reinterpret_cast(context)->checker->AsETSChecker())-> diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 1c983f33ff3eefff985deb7895c814f3b3723f01..e76765bc40e466974dff29f58350ec0b7af5478c 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -212,10 +212,20 @@ __attribute__((unused)) char const *ArenaStrdup(ArenaAllocator *allocator, char return res; } -extern "C" es2panda_Config *CreateConfig(int args, char const *const *argv) +extern "C" void MemInitialize() { mem::MemConfig::Initialize(0, 0, COMPILER_SIZE, 0, 0, 0); PoolManager::Initialize(PoolType::MMAP); +} + +extern "C" void MemFinalize() +{ + PoolManager::Finalize(); + mem::MemConfig::Finalize(); +} + +extern "C" es2panda_Config *CreateConfig(int args, char const *const *argv) +{ auto diagnosticEngine = new util::DiagnosticEngine(); auto *options = new util::Options(argv[0], *diagnosticEngine); if (!options->Parse(Span(argv, args))) { @@ -233,9 +243,6 @@ extern "C" es2panda_Config *CreateConfig(int args, char const *const *argv) extern "C" void DestroyConfig(es2panda_Config *config) { - PoolManager::Finalize(); - mem::MemConfig::Finalize(); - auto *cfg = reinterpret_cast(config); if (cfg == nullptr) { return; @@ -263,15 +270,33 @@ static void CompileJob(public_lib::Context *context, varbinder::FunctionScope *s funcEmitter.Generate(); } +static void GenerateStdLibCache(es2panda_Config *config, GlobalContext *globalContext, [[maybe_unused]]bool LspUsage); + +extern "C" __attribute__((unused)) es2panda_GlobalContext *CreateGlobalContext(es2panda_Config *config, + const char **externalFileList, + size_t fileNum, bool LspUsage) +{ + auto *globalContext = new GlobalContext; + for (size_t i = 0; i < fileNum; i++) { + auto fileName = externalFileList[i]; + auto globalAllocator = new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + globalContext->cachedExternalPrograms.emplace(fileName, nullptr); + globalContext->externalProgramAllocators.emplace(fileName, globalAllocator); + } + + GenerateStdLibCache(config, globalContext, LspUsage); + + return reinterpret_cast(globalContext); +} + __attribute__((unused)) static es2panda_Context *CreateContext(es2panda_Config *config, std::string &&source, - const char *fileName) + const char *fileName, + es2panda_GlobalContext *globalContext, bool isExternal, + bool genStdLib) { auto *cfg = reinterpret_cast(config); auto *res = new Context; - res->input = std::move(source); - res->sourceFileName = fileName; - res->config = cfg; - + res->compiledByCapi = true; if (cfg == nullptr) { res->errorMessage = "Config is nullptr."; res->state = ES2PANDA_STATE_ERROR; @@ -284,57 +309,103 @@ __attribute__((unused)) static es2panda_Context *CreateContext(es2panda_Config * return reinterpret_cast(res); } + res->config = cfg; + res->isExternal = isExternal; + res->globalContext = reinterpret_cast(globalContext); + + res->input = std::move(source); + res->sourceFileName = fileName; res->sourceFile = new SourceFile(res->sourceFileName, res->input, cfg->options->IsModule()); - res->allocator = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + if (isExternal) { + ir::g_mainFileDisableHistory = false; + ES2PANDA_ASSERT(res->globalContext != nullptr); + if (genStdLib) { + ES2PANDA_ASSERT(res->globalContext->stdLibAllocator != nullptr); + res->allocator = res->globalContext->stdLibAllocator; + } else { + ES2PANDA_ASSERT(res->globalContext->externalProgramAllocators.count(fileName) != 0); + ES2PANDA_ASSERT(res->globalContext->externalProgramAllocators[fileName]->Type()); + res->allocator = reinterpret_cast(res->globalContext->externalProgramAllocators[fileName]); + } + } else { + ir::g_mainFileDisableHistory = true; + res->allocator = new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + } + + res->phaseManager = new compiler::PhaseManager(ScriptExtension::ETS, res->allocator); res->queue = new compiler::CompileQueue(cfg->options->GetThread()); auto *varbinder = res->allocator->New(res->allocator); - res->parserProgram = new parser::Program(res->allocator, varbinder); + res->parserProgram = res->allocator->New(res->allocator, varbinder); res->diagnosticEngine = cfg->diagnosticEngine; res->parser = new parser::ETSParser(res->parserProgram, *cfg->options, *cfg->diagnosticEngine, parser::ParserStatus::NO_OPTS); - res->checker = new checker::ETSChecker(*res->diagnosticEngine); - res->analyzer = new checker::ETSAnalyzer(res->checker); - res->checker->SetAnalyzer(res->analyzer); + res->parser->SetContext(res); + res->PushChecker(res->allocator->New(*res->diagnosticEngine)); + res->PushAnalyzer(res->allocator->New(res->GetChecker())); + res->GetChecker()->SetAnalyzer(res->GetAnalyzer()); varbinder->SetProgram(res->parserProgram); varbinder->SetContext(res); res->codeGenCb = CompileJob; - res->phaseManager = new compiler::PhaseManager(ScriptExtension::ETS, res->allocator); + res->emitter = new compiler::ETSEmitter(res); res->program = nullptr; res->state = ES2PANDA_STATE_NEW; return reinterpret_cast(res); } -extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromFile(es2panda_Config *config, - char const *sourceFileName) +__attribute__((unused)) static std::stringstream ReadFile(char const *sourceFileName, Context *&res) { std::ifstream inputStream; inputStream.open(sourceFileName); if (inputStream.fail()) { - auto *res = new Context; + res = new Context; res->errorMessage = "Failed to open file: "; res->errorMessage.append(sourceFileName); - return reinterpret_cast(res); } std::stringstream ss; ss << inputStream.rdbuf(); if (inputStream.fail()) { - auto *res = new Context; + res = new Context; res->errorMessage = "Failed to read file: "; res->errorMessage.append(sourceFileName); + } + return ss; +} + +extern "C" __attribute__((unused)) es2panda_Context *CreateCacheContextFromFile(es2panda_Config *config, + char const *sourceFileName, + es2panda_GlobalContext *globalContext, + bool isExternal) +{ + Context *res = nullptr; + auto ss = ReadFile(sourceFileName, res); + if (res != nullptr) { return reinterpret_cast(res); } - return CreateContext(config, ss.str(), sourceFileName); + return CreateContext(config, ss.str(), sourceFileName, globalContext, isExternal, false); +} + +extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromFile(es2panda_Config *config, + char const *sourceFileName) +{ + Context *res = nullptr; + auto ss = ReadFile(sourceFileName, res); + if (res != nullptr) { + return reinterpret_cast(res); + ; + } + + return CreateContext(config, ss.str(), sourceFileName, nullptr, false, false); } extern "C" __attribute__((unused)) es2panda_Context *CreateContextFromString(es2panda_Config *config, const char *source, char const *fileName) { // NOTE: gogabr. avoid copying source. - return CreateContext(config, std::string(source), fileName); + return CreateContext(config, std::string(source), fileName, nullptr, false, false); } __attribute__((unused)) static Context *Parse(Context *ctx) @@ -346,9 +417,27 @@ __attribute__((unused)) static Context *Parse(Context *ctx) } ctx->phaseManager->Restart(); - ctx->parser->ParseScript(*ctx->sourceFile, - ctx->config->options->GetCompilationMode() == CompilationMode::GEN_STD_LIB); - ctx->state = ES2PANDA_STATE_PARSED; + if (ctx->isExternal && ctx->allocator != ctx->globalContext->stdLibAllocator) { + auto allocator = ctx->allocator; + auto ident = allocator->New(compiler::Signatures::ETS_GLOBAL, allocator); + ArenaVector stmts(allocator->Adapter()); + auto etsModule = allocator->New(allocator, std::move(stmts), ident, ir::ModuleFlag::ETSSCRIPT, + ctx->parserProgram); + ctx->parserProgram->SetAst(etsModule); + util::ImportPathManager::ImportMetadata importData {util::ImportFlags::NONE}; + importData.resolvedSource = ctx->sourceFileName; + importData.lang = Language::Id::ETS; + importData.declPath = util::ImportPathManager::DUMMY_PATH; + importData.ohmUrl = util::ImportPathManager::DUMMY_PATH; + ctx->parser->AsETSParser()->GetImportPathManager()->AddToParseList(importData); + ctx->parser->AsETSParser()->AddExternalSource(ctx->parser->AsETSParser()->ParseSources(true)); + } else { + ctx->parser->ParseScript(*ctx->sourceFile, + ctx->config->options->GetCompilationMode() == CompilationMode::GEN_STD_LIB); + } + ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_PARSED : ES2PANDA_STATE_ERROR; + ctx->diagnosticEngine->FlushDiagnostic(); + ctx->phaseManager->SetCurrentPhaseIdToJSPlugin1(); return ctx; } @@ -379,6 +468,7 @@ __attribute__((unused)) static Context *Check(Context *ctx) } if (ctx->state == ES2PANDA_STATE_ERROR) { + ctx->diagnosticEngine->FlushDiagnostic(); return ctx; } @@ -389,10 +479,32 @@ __attribute__((unused)) static Context *Check(Context *ctx) } phase->Apply(ctx, ctx->parserProgram); } + ctx->phaseManager->SetCurrentPhaseIdToJSPlugin3(); ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_CHECKED : ES2PANDA_STATE_ERROR; return ctx; } +__attribute__((unused)) static void SaveCache(Context *ctx) +{ + if (ctx->allocator == ctx->globalContext->stdLibAllocator) { + return; + } + ES2PANDA_ASSERT(ctx->globalContext != nullptr && + ctx->globalContext->cachedExternalPrograms.count(ctx->sourceFileName) != 0); + ctx->globalContext->cachedExternalPrograms[ctx->sourceFileName] = &(ctx->parserProgram->ExternalSources()); + + // cycle dependencies + for (auto &[_, extPrograms] : ctx->parserProgram->ExternalSources()) { + for (auto extProgram : extPrograms) { + auto absPath = std::string {extProgram->AbsoluteName()}; + auto &cacheMap = ctx->globalContext->cachedExternalPrograms; + if (cacheMap.count(absPath) == 1 && cacheMap[absPath] == nullptr) { + cacheMap[absPath] = &(ctx->parserProgram->ExternalSources()); + } + } + } +} + __attribute__((unused)) static Context *Lower(Context *ctx) { if (ctx->state < ES2PANDA_STATE_CHECKED) { @@ -400,6 +512,7 @@ __attribute__((unused)) static Context *Lower(Context *ctx) } if (ctx->state == ES2PANDA_STATE_ERROR) { + ctx->diagnosticEngine->FlushDiagnostic(); return ctx; } @@ -408,6 +521,16 @@ __attribute__((unused)) static Context *Lower(Context *ctx) phase->Apply(ctx, ctx->parserProgram); } ctx->state = !ctx->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_LOWERED : ES2PANDA_STATE_ERROR; + + for (auto &[_, extPrograms] : ctx->parserProgram->ExternalSources()) { + for (auto &extProgram : extPrograms) { + extProgram->MarkASTAsLowered(); + } + } + if (ctx->isExternal) { + SaveCache(ctx); + } + return ctx; } @@ -503,17 +626,27 @@ extern "C" __attribute__((unused)) void DestroyContext(es2panda_Context *context auto *ctx = reinterpret_cast(context); delete ctx->program; delete ctx->emitter; - delete ctx->analyzer; - delete ctx->checker; delete ctx->parser; - delete ctx->parserProgram; delete ctx->queue; - delete ctx->allocator; delete ctx->sourceFile; delete ctx->phaseManager; + if (!ctx->isExternal) { + delete ctx->allocator; + } delete ctx; } +extern "C" __attribute__((unused)) void DestroyGlobalContext(es2panda_GlobalContext *globalContext) +{ + auto *globalCtx = reinterpret_cast(globalContext); + for (auto [_, alloctor] : globalCtx->externalProgramAllocators) { + delete alloctor; + } + + delete globalCtx->stdLibAllocator; + delete globalCtx; +} + extern "C" __attribute__((unused)) es2panda_ContextState ContextState(es2panda_Context *context) { auto *s = reinterpret_cast(context); @@ -799,7 +932,7 @@ extern "C" void AstNodeRecheck(es2panda_Context *ctx, es2panda_AstNode *node) auto E2pNode = reinterpret_cast(node); auto context = reinterpret_cast(ctx); auto varbinder = context->parserProgram->VarBinder()->AsETSBinder(); - auto checker = context->checker->AsETSChecker(); + auto checker = context->GetChecker()->AsETSChecker(); auto phaseManager = context->phaseManager; if (E2pNode->IsScriptFunction() || E2pNode->FindChild([](ir::AstNode *n) { return n->IsScriptFunction(); }) != nullptr) { @@ -807,7 +940,9 @@ extern "C" void AstNodeRecheck(es2panda_Context *ctx, es2panda_AstNode *node) E2pNode = E2pNode->Parent(); } } - compiler::Recheck(phaseManager, varbinder, checker, E2pNode); + if (!context->parserProgram->IsStdLib()) { + compiler::Recheck(phaseManager, varbinder, checker, E2pNode); + } context->state = !context->diagnosticEngine->IsAnyError() ? ES2PANDA_STATE_CHECKED : ES2PANDA_STATE_ERROR; return; } @@ -962,7 +1097,7 @@ extern "C" __attribute__((unused)) int GenerateTsDeclarationsFromContext(es2pand const char *outputEts, bool exportAll) { auto *ctxImpl = reinterpret_cast(ctx); - auto *checker = reinterpret_cast(ctxImpl->checker); + auto *checker = reinterpret_cast(ctxImpl->GetChecker()); ark::es2panda::declgen_ets2ts::DeclgenOptions declgenOptions; declgenOptions.exportAll = exportAll; @@ -994,7 +1129,8 @@ extern "C" void InsertETSImportDeclarationAndParse(es2panda_Context *context, es auto *importDeclE2p = reinterpret_cast(importDeclaration); importDeclE2p->AddAstNodeFlags(ir::AstNodeFlags::NOCLEANUP); - parserProgram->Ast()->Statements().insert(parserProgram->Ast()->Statements().begin(), importDeclE2p); + auto &stmt = parserProgram->Ast()->StatmentsForUpdates(); + stmt.insert(stmt.begin(), importDeclE2p); importDeclE2p->SetParent(parserProgram->Ast()); ctx->parser->AsETSParser()->AddExternalSource(ctx->parser->AsETSParser()->ParseSources()); @@ -1004,16 +1140,58 @@ extern "C" void InsertETSImportDeclarationAndParse(es2panda_Context *context, es } } +__attribute__((unused)) static void PushCheckerAndVarBinder(parser::Program *prog) +{ + auto checker = prog->FirstChecker(); + auto varbinder = prog->FirstVarBinder(); + + varbinder->GetContext()->PushChecker(checker); + prog->PushChecker(checker); + prog->PushVarBinder(1, varbinder); + + varbinder->GetContext()->PushChecker(checker); + prog->PushChecker(checker); + prog->PushVarBinder(2, varbinder); +} + +__attribute__((unused)) static void GenerateStdLibCache(es2panda_Config *config, GlobalContext *globalContext, + [[maybe_unused]]bool LspUsage) +{ + auto cfg = reinterpret_cast(config); + globalContext->stdLibAllocator = new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + auto ctx = CreateContext(config, std::move(""), cfg->options->SourceFileName().c_str(), + reinterpret_cast(globalContext), true, true); + ProceedToState(ctx, es2panda_ContextState::ES2PANDA_STATE_CHECKED); + for (auto [_, program_list] : reinterpret_cast(ctx)->parserProgram->ExternalSources()) { + for (auto &prog : program_list) { + PushCheckerAndVarBinder(prog); + } + } + + PushCheckerAndVarBinder(reinterpret_cast(ctx)->parserProgram); + reinterpret_cast(ctx)->phaseManager->SetCurrentPhaseId(0); + reinterpret_cast(ctx)->phaseManager->SetCurrentPhaseId(1); + reinterpret_cast(ctx)->phaseManager->SetCurrentPhaseId(0); + ProceedToState(ctx, es2panda_ContextState::ES2PANDA_STATE_LOWERED); + globalContext->stdLibAstCache = &(reinterpret_cast(ctx)->parserProgram->ExternalSources()); + DestroyContext(ctx); +} + es2panda_Impl g_impl = { ES2PANDA_LIB_VERSION, + MemInitialize, + MemFinalize, CreateConfig, DestroyConfig, ConfigGetOptions, CreateContextFromFile, + CreateCacheContextFromFile, CreateContextFromString, ProceedToState, DestroyContext, + CreateGlobalContext, + DestroyGlobalContext, ContextState, ContextErrorMessage, ContextProgram, @@ -1067,6 +1245,16 @@ es2panda_Impl g_impl = { }; +checker::Checker *Context::GetChecker() const +{ + return checkers_[compiler::GetPhaseManager()->GetCurrentMajor()]; +} + +checker::SemanticAnalyzer *Context::GetAnalyzer() const +{ + return analyzers_[compiler::GetPhaseManager()->GetCurrentMajor()]; +} + } // namespace ark::es2panda::public_lib extern "C" es2panda_Impl const *es2panda_GetImpl(int version) diff --git a/ets2panda/public/es2panda_lib.h b/ets2panda/public/es2panda_lib.h index b0061ef673d2621a9f5713ac965c378cfdc3115b..f2695bb1d6e4ceb59ecd5b907ea6f8a68fb6b964 100644 --- a/ets2panda/public/es2panda_lib.h +++ b/ets2panda/public/es2panda_lib.h @@ -43,6 +43,7 @@ extern "C" { typedef struct es2panda_Config es2panda_Config; typedef struct es2panda_Context es2panda_Context; +typedef struct es2panda_GlobalContext es2panda_GlobalContext; typedef struct es2panda_variantDoubleCharArrayBool { int index; @@ -163,15 +164,24 @@ typedef enum es2panda_ContextState es2panda_ContextState; struct CAPI_EXPORT es2panda_Impl { int version; + void (*MemInitialize)(); + void (*MemFinalize)(); + es2panda_Config *(*CreateConfig)(int argc, char const *const *argv); void (*DestroyConfig)(es2panda_Config *config); const es2panda_Options *(*ConfigGetOptions)(es2panda_Config *config); es2panda_Context *(*CreateContextFromFile)(es2panda_Config *config, char const *source_file_name); + es2panda_Context *(*CreateCacheContextFromFile)(es2panda_Config *config, char const *source_file_name, + es2panda_GlobalContext *globalContext, bool isExternal); es2panda_Context *(*CreateContextFromString)(es2panda_Config *config, const char *source, char const *file_name); es2panda_Context *(*ProceedToState)(es2panda_Context *context, es2panda_ContextState state); // context is consumed void (*DestroyContext)(es2panda_Context *context); + es2panda_GlobalContext *(*CreateGlobalContext)(es2panda_Config *config, const char **externalFileList, + size_t fileNum, bool LspUsage); + void (*DestroyGlobalContext)(es2panda_GlobalContext *globalContext); + es2panda_ContextState (*ContextState)(es2panda_Context *context); char const *(*ContextErrorMessage)(es2panda_Context *context); diff --git a/ets2panda/public/headers_parser/cpp_keywords.py b/ets2panda/public/headers_parser/cpp_keywords.py index dc0e412c2b204f4f2365762eff06f1b1c5dfc2af..280b7ec43e4a949d431af08dc4bcc75c1bfdb1d1 100644 --- a/ets2panda/public/headers_parser/cpp_keywords.py +++ b/ets2panda/public/headers_parser/cpp_keywords.py @@ -31,6 +31,9 @@ known_macroses = [ "DEFAULT_COPY_SEMANTIC", "VARIABLE_TYPES", "DECLARATION_KINDS", + "SETTER_FOR_FIELD", + "SETTER_FOR_CHILD", + "SETTER_FOR_ARENAVECTOR_CHILD", ] modifiers_list = [ diff --git a/ets2panda/public/public.h b/ets2panda/public/public.h index 7ed0b160dcfdc2bc6528a40aeb0525cc3a2f4efd..79d139aa5b49a16c3e1204a995c218341dff34b5 100644 --- a/ets2panda/public/public.h +++ b/ets2panda/public/public.h @@ -32,6 +32,8 @@ class Options; namespace ark::es2panda::compiler { class PhaseManager; +void SetPhaseManager(PhaseManager *phaseManager); +PhaseManager *GetPhaseManager(); } // namespace ark::es2panda::compiler namespace ark::es2panda::public_lib { @@ -41,15 +43,25 @@ struct ConfigImpl { std::list diagnosticKindStorage; }; +using ExternalSource = ArenaUnorderedMap>; + +struct GlobalContext { + std::unordered_map externalProgramAllocators; + std::unordered_map cachedExternalPrograms; + ThreadSafeArenaAllocator *stdLibAllocator = nullptr; + ExternalSource *stdLibAstCache = nullptr; +}; + struct Context { using CodeGenCb = std::function; - + // NOLINTBEGIN ConfigImpl *config = nullptr; + GlobalContext *globalContext = nullptr; std::string sourceFileName; std::string input; SourceFile const *sourceFile = nullptr; - ArenaAllocator *allocator = nullptr; + ThreadSafeArenaAllocator *allocator = nullptr; compiler::CompileQueue *queue = nullptr; std::vector const *plugins = nullptr; std::vector contextLiterals; @@ -58,8 +70,8 @@ struct Context { parser::Program *parserProgram = nullptr; parser::ParserImpl *parser = nullptr; - checker::Checker *checker = nullptr; - checker::SemanticAnalyzer *analyzer = nullptr; + // checker::Checker *checker = nullptr; + // checker::SemanticAnalyzer *analyzer = nullptr; compiler::Emitter *emitter = nullptr; pandasm::Program *program = nullptr; util::DiagnosticEngine *diagnosticEngine = nullptr; @@ -67,7 +79,45 @@ struct Context { es2panda_ContextState state = ES2PANDA_STATE_NEW; std::string errorMessage; lexer::SourcePosition errorPos; + bool isExternal = false; + bool compiledByCapi = false; + + // NOLINTEND + + checker::Checker *GetChecker() const; + + void PushChecker(checker::Checker *checker) + { + parserProgram->PushChecker(checker); + checkers_.push_back(checker); + } + + void DestoryCheckers() + { + for (auto item : checkers_) { + delete item; + } + } + + checker::SemanticAnalyzer *GetAnalyzer() const; + + void PushAnalyzer(checker::SemanticAnalyzer *analyzer) + { + return analyzers_.push_back(analyzer); + } + + void DestoryAnalyzers() + { + for (auto item : analyzers_) { + delete item; + } + } + +private: + std::vector checkers_; + std::vector analyzers_; }; + } // namespace ark::es2panda::public_lib #endif diff --git a/ets2panda/test/ast/parser/ets/re_export/re_export_4.ets b/ets2panda/test/ast/parser/ets/re_export/re_export_4.ets index cf271b95faea3ba1ac14a870b34a155b0e972a23..6019045f4e66840ee96f4ef6efb38b0e62d763c2 100644 --- a/ets2panda/test/ast/parser/ets/re_export/re_export_4.ets +++ b/ets2panda/test/ast/parser/ets/re_export/re_export_4.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -export {foo} from "./export" -export /* @@ label */{foo} from "./export_2" +export /* @@ label */{foo} from "./export" +export {foo} from "./export_2" /* @@@ label Error TypeError: Ambiguous export "foo" */ diff --git a/ets2panda/test/parser/ets/re_export/import_10-expected.txt b/ets2panda/test/parser/ets/re_export/import_10-expected.txt index 2b576345b7480be4dcb8aa068b8c11cdd060185f..7fffcfa3362cac1cc7a7f9db8d22b49ed216e547 100644 --- a/ets2panda/test/parser/ets/re_export/import_10-expected.txt +++ b/ets2panda/test/parser/ets/re_export/import_10-expected.txt @@ -374,4 +374,4 @@ } } } -TypeError: Ambiguous export "foo" [re_export_4.ets:17:8] +TypeError: Ambiguous export "foo" [re_export_4.ets:16:8] diff --git a/ets2panda/test/parser/ets/re_export/re_export_4-expected.txt b/ets2panda/test/parser/ets/re_export/re_export_4-expected.txt index 1921e61a4d3bad1c0e9f3048718b82cf5524968c..f2fa296b70cc2f492a45ea02d70a600d7674cac0 100644 --- a/ets2panda/test/parser/ets/re_export/re_export_4-expected.txt +++ b/ets2panda/test/parser/ets/re_export/re_export_4-expected.txt @@ -471,4 +471,4 @@ } } } -TypeError: Ambiguous export "foo" [re_export_4.ets:17:8] +TypeError: Ambiguous export "foo" [re_export_4.ets:16:8] diff --git a/ets2panda/test/unit/lowerings/node_history.cpp b/ets2panda/test/unit/lowerings/node_history.cpp index c3b982aa63f37c06a973606c199c648cf3014966..3be840016439301dff1e7893b566cf53f2b737a6 100644 --- a/ets2panda/test/unit/lowerings/node_history.cpp +++ b/ets2panda/test/unit/lowerings/node_history.cpp @@ -54,12 +54,13 @@ private: std::unique_ptr phaseManager_; }; -constexpr int32_t PHASE_ID_0 = 0; -constexpr int32_t PHASE_ID_1 = 1; -constexpr int32_t PHASE_ID_2 = 2; -constexpr int32_t PHASE_ID_3 = 3; -constexpr int32_t PHASE_ID_4 = 4; -constexpr int32_t PHASE_ID_5 = 5; +constexpr compiler::PhaseId PARSER_PHASE_ID = {0, compiler::PARSER_PHASE_ID}; +constexpr compiler::PhaseId PHASE_ID_0 = {0, 0}; +constexpr compiler::PhaseId PHASE_ID_1 = {0, 1}; +constexpr compiler::PhaseId PHASE_ID_2 = {0, 2}; +constexpr compiler::PhaseId PHASE_ID_3 = {0, 3}; +constexpr compiler::PhaseId PHASE_ID_4 = {0, 4}; +constexpr compiler::PhaseId PHASE_ID_5 = {0, 5}; constexpr int32_t INDEX_0 = 0; constexpr int32_t INDEX_1 = 1; @@ -149,26 +150,26 @@ TEST_F(NodeHistoryTest, DoubleLinkedList) TEST_F(NodeHistoryTest, HistoryAt) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier = Allocator()->New(Allocator())->AsIdentifier(); auto history = Allocator()->New(identifier, PhaseManager()->CurrentPhaseId(), Allocator()); - ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->At(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->At(PHASE_ID_0), identifier); ASSERT_EQ(history->At(PHASE_ID_1), nullptr); } TEST_F(NodeHistoryTest, HistoryGet) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier = Allocator()->New(Allocator())->AsIdentifier(); auto history = Allocator()->New(identifier, PhaseManager()->CurrentPhaseId(), Allocator()); - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->Get(PHASE_ID_0), identifier); ASSERT_EQ(history->Get(PHASE_ID_1), identifier); ASSERT_EQ(history->Get(PHASE_ID_2), identifier); @@ -178,25 +179,25 @@ TEST_F(NodeHistoryTest, HistoryGet) // CC-OFFNXT(huge_method, G.FUN.01-CPP, G.FUD.05) solid logic TEST_F(NodeHistoryTest, HistorySet) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier0 = Allocator()->New(Allocator())->AsIdentifier(); auto history = Allocator()->New(identifier0, PhaseManager()->CurrentPhaseId(), Allocator()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); auto identifier1 = Allocator()->New(Allocator())->AsIdentifier(); history->Set(identifier1, PhaseManager()->CurrentPhaseId()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); auto identifier2 = Allocator()->New(Allocator())->AsIdentifier(); history->Set(identifier2, PhaseManager()->CurrentPhaseId()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_3); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_3.minor); history->Set(nullptr, PhaseManager()->CurrentPhaseId()); // Search forward - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->Get(PHASE_ID_0), identifier0); ASSERT_EQ(history->Get(PHASE_ID_1), identifier1); ASSERT_EQ(history->Get(PHASE_ID_2), identifier2); @@ -211,7 +212,7 @@ TEST_F(NodeHistoryTest, HistorySet) ASSERT_EQ(history->Get(PHASE_ID_2), identifier2); ASSERT_EQ(history->Get(PHASE_ID_1), identifier1); ASSERT_EQ(history->Get(PHASE_ID_0), identifier0); - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); // Search random ASSERT_EQ(history->Get(PHASE_ID_1), identifier1); @@ -219,11 +220,11 @@ TEST_F(NodeHistoryTest, HistorySet) ASSERT_EQ(history->Get(PHASE_ID_2), identifier2); ASSERT_EQ(history->Get(PHASE_ID_4), nullptr); ASSERT_EQ(history->Get(PHASE_ID_0), identifier0); - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->Get(PHASE_ID_3), nullptr); // Search precise - ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->At(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->At(PHASE_ID_0), identifier0); ASSERT_EQ(history->At(PHASE_ID_1), identifier1); ASSERT_EQ(history->At(PHASE_ID_2), identifier2); @@ -234,47 +235,54 @@ TEST_F(NodeHistoryTest, HistorySet) TEST_F(NodeHistoryTest, HistoryReplace) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier0Orig = Allocator()->New(Allocator())->AsIdentifier(); auto history = Allocator()->New(identifier0Orig, PhaseManager()->CurrentPhaseId(), Allocator()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); auto identifier1Orig = Allocator()->New(Allocator())->AsIdentifier(); history->Set(identifier1Orig, PhaseManager()->CurrentPhaseId()); - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->Get(PHASE_ID_0), identifier0Orig); ASSERT_EQ(history->Get(PHASE_ID_1), identifier1Orig); ASSERT_EQ(history->Get(PHASE_ID_2), identifier1Orig); ASSERT_EQ(history->Get(PHASE_ID_3), identifier1Orig); - ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->At(PARSER_PHASE_ID), nullptr); ASSERT_EQ(history->At(PHASE_ID_0), identifier0Orig); ASSERT_EQ(history->At(PHASE_ID_1), identifier1Orig); ASSERT_EQ(history->At(PHASE_ID_2), nullptr); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier0New = Allocator()->New(Allocator())->AsIdentifier(); history->Set(identifier0New, PhaseManager()->CurrentPhaseId()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); auto identifier1New = Allocator()->New(Allocator())->AsIdentifier(); history->Set(identifier1New, PhaseManager()->CurrentPhaseId()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); history->Set(nullptr, PhaseManager()->CurrentPhaseId()); - ASSERT_EQ(history->Get(compiler::PARSER_PHASE_ID), nullptr); - ASSERT_EQ(history->Get(PHASE_ID_0), identifier0New); - ASSERT_EQ(history->Get(PHASE_ID_1), identifier1New); - ASSERT_EQ(history->Get(PHASE_ID_2), nullptr); - ASSERT_EQ(history->Get(PHASE_ID_3), nullptr); + ASSERT_EQ(history->Get(PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->Get(PHASE_ID_0), identifier0Orig); + ASSERT_EQ(history->Get(PHASE_ID_1), identifier1Orig); + ASSERT_EQ(history->Get(PHASE_ID_2), identifier1Orig); + ASSERT_EQ(history->Get(PHASE_ID_3), identifier1Orig); + ASSERT_EQ(history->Get({1, PHASE_ID_0.minor}), identifier0New); + ASSERT_EQ(history->Get({1, PHASE_ID_1.minor}), identifier1New); + ASSERT_EQ(history->Get({1, PHASE_ID_2.minor}), nullptr); + ASSERT_EQ(history->Get({1, PHASE_ID_3.minor}), nullptr); - ASSERT_EQ(history->At(compiler::PARSER_PHASE_ID), nullptr); - ASSERT_EQ(history->At(PHASE_ID_0), identifier0New); - ASSERT_EQ(history->At(PHASE_ID_1), identifier1New); + ASSERT_EQ(history->At(PARSER_PHASE_ID), nullptr); + ASSERT_EQ(history->At(PHASE_ID_0), identifier0Orig); + ASSERT_EQ(history->At(PHASE_ID_1), identifier1Orig); + ASSERT_EQ(history->At(PHASE_ID_2), nullptr); + ASSERT_EQ(history->At({1, PHASE_ID_0.minor}), identifier0New); + ASSERT_EQ(history->At({1, PHASE_ID_1.minor}), identifier1New); ASSERT_EQ(history->At(PHASE_ID_2), nullptr); } @@ -288,9 +296,9 @@ ir::ClassDefinition *NewClassDefinition(ArenaAllocator *allocator) } /// NOTE(mivanov): To be enabled after #24153/#24424 implemented -TEST_F(NodeHistoryTest, DISABLED_UpdateField) +TEST_F(NodeHistoryTest, UpdateField) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); auto definition = NewClassDefinition(Allocator()); ASSERT_FALSE(definition->IsAbstract()); @@ -299,19 +307,19 @@ TEST_F(NodeHistoryTest, DISABLED_UpdateField) definition->AddModifier(ir::ModifierFlags::FINAL); ASSERT_TRUE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); definition->AddModifier(ir::ModifierFlags::ABSTRACT); ASSERT_TRUE(definition->IsAbstract()); definition->ClearModifier(ir::ModifierFlags::FINAL); ASSERT_FALSE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); definition->ClearModifier(ir::ModifierFlags::ABSTRACT); ASSERT_FALSE(definition->IsAbstract()); definition->AddModifier(ir::ModifierFlags::FINAL); ASSERT_TRUE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); definition->ClearModifier(ir::ModifierFlags::FINAL); ASSERT_FALSE(definition->IsFinal()); @@ -319,15 +327,15 @@ TEST_F(NodeHistoryTest, DISABLED_UpdateField) ASSERT_FALSE(definition->IsAbstract()); ASSERT_TRUE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); ASSERT_TRUE(definition->IsAbstract()); ASSERT_FALSE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); ASSERT_FALSE(definition->IsAbstract()); ASSERT_TRUE(definition->IsFinal()); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); ASSERT_FALSE(definition->IsAbstract()); ASSERT_FALSE(definition->IsFinal()); } @@ -335,36 +343,36 @@ TEST_F(NodeHistoryTest, DISABLED_UpdateField) /// NOTE(mivanov): To be enabled after #24153/#24424 implemented TEST_F(NodeHistoryTest, DISABLED_UpdateChild) { - ASSERT_EQ(PhaseManager()->CurrentPhaseId(), compiler::PARSER_PHASE_ID); + ASSERT_EQ(PhaseManager()->CurrentPhaseId(), PARSER_PHASE_ID); auto declaration = Allocator()->New(NewClassDefinition(Allocator()), Allocator())->AsClassDeclaration(); ASSERT_EQ(declaration->Definition()->Ident(), nullptr); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); auto identifier0 = Allocator()->New(Allocator())->AsIdentifier(); declaration->Definition()->SetIdent(identifier0); ASSERT_EQ(declaration->Definition()->Ident(), identifier0); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); auto identifier1 = Allocator()->New(Allocator())->AsIdentifier(); declaration->Definition()->SetIdent(identifier1); ASSERT_EQ(declaration->Definition()->Ident(), identifier1); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); declaration->Definition()->SetIdent(nullptr); ASSERT_EQ(declaration->Definition()->Ident(), nullptr); PhaseManager()->Restart(); ASSERT_EQ(declaration->Definition()->Ident(), nullptr); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_0); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_0.minor); ASSERT_EQ(declaration->Definition()->Ident(), identifier0); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_1); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_1.minor); ASSERT_EQ(declaration->Definition()->Ident(), identifier1); - PhaseManager()->SetCurrentPhaseId(PHASE_ID_2); + PhaseManager()->SetCurrentPhaseId(PHASE_ID_2.minor); ASSERT_EQ(declaration->Definition()->Ident(), nullptr); } } // namespace ark::es2panda diff --git a/ets2panda/test/unit/lsp/lsp_api_test.cpp b/ets2panda/test/unit/lsp/lsp_api_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a346bb616a0914dec494bf659df68f26fdcedb7e --- /dev/null +++ b/ets2panda/test/unit/lsp/lsp_api_test.cpp @@ -0,0 +1,670 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lsp_api_test.h" + +#include +#include + +#include "ir/astNode.h" +#include "lsp/include/internal_api.h" +#include "public/es2panda_lib.h" +#include "public/public.h" + +using ark::es2panda::lsp::Initializer; + +TEST_F(LSPAPITests, GetTouchingToken1) +{ + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("not-found-node.ets", ES2PANDA_STATE_CHECKED, + "function A(a:number, b:number) {\n return a + b;\n}\nA(1, 2);"); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + size_t const offset = 50; + auto result = ark::es2panda::lsp::GetTouchingToken(ctx, offset, false); + ASSERT_EQ(result, nullptr); + + auto result1 = ark::es2panda::lsp::GetTouchingToken(ctx, offset, true); + ASSERT_EQ(result1, nullptr); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetTouchingToken2) +{ + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("nested-node.ets", ES2PANDA_STATE_CHECKED, + "function A(a:number, b:number) {\n return a + b;\n}\nA(1, 2);"); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + size_t const offset = 51; + auto result = ark::es2panda::lsp::GetTouchingToken(ctx, offset, false); + auto ast = GetAstFromContext(ctx); + auto expectedNode = ast->FindChild( + [](ark::es2panda::ir::AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "A"; }); + ASSERT_EQ(result->DumpJSON(), expectedNode->DumpJSON()); + ASSERT_EQ(result->Start().index, expectedNode->Start().index); + ASSERT_EQ(result->End().index, expectedNode->End().index); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetTouchingToken3) +{ + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("first-node.ets", ES2PANDA_STATE_CHECKED, + "function A(a:number, b:number) {\n return a + b;\n}\nA(1, 2);"); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + size_t const offset = 51; + auto result = ark::es2panda::lsp::GetTouchingToken(ctx, offset, true); + auto ast = GetAstFromContext(ctx); + auto expectedNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) { return node->IsExpressionStatement(); }); + ASSERT_EQ(result->DumpJSON(), expectedNode->DumpJSON()); + ASSERT_EQ(result->Start().index, expectedNode->Start().index); + ASSERT_EQ(result->End().index, expectedNode->End().index); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, DiagnosticConstructorAndField) +{ + int const errorCode = 404; + int const defaultCharacter = 10; + std::vector tags {}; + std::vector relatedInfoList {}; + Diagnostic diagnostic(range_, tags, relatedInfoList, DiagnosticSeverity::Error, errorCode, message_); + + EXPECT_EQ(diagnostic.range_.start.line_, 1); + EXPECT_EQ(diagnostic.range_.end.character_, defaultCharacter); + EXPECT_EQ(diagnostic.message_, message_); + EXPECT_EQ(diagnostic.severity_, DiagnosticSeverity::Error); + EXPECT_EQ(std::get(diagnostic.code_), errorCode); +} + +TEST_F(LSPAPITests, DiagnosticCodeDescriptionOptional) +{ + CodeDescription codeDesc; + codeDesc.href_ = "http://example.com/error/404"; + int const errorCode = 404; + std::vector tags {}; + std::vector relatedInfoList {}; + + Diagnostic diagnostic(range_, tags, relatedInfoList, DiagnosticSeverity::Error, errorCode, message_, codeDesc); + + const auto &codeDescription = diagnostic.codeDescription_; + EXPECT_EQ(codeDescription.href_, "http://example.com/error/404"); +} + +TEST_F(LSPAPITests, DiagnosticTagsAndRelatedInformation) +{ + std::vector tags {}; + tags.push_back(DiagnosticTag::Unnecessary); + std::vector relatedInfoList {}; + DiagnosticRelatedInformation relatedInfo; + relatedInfo.location_ = Location {"www.test.uri", range_}; + relatedInfo.message_ = "Related information message"; + relatedInfoList.push_back(relatedInfo); + int const errorCode = 200; + CodeDescription des = {}; + + Diagnostic diagnostic(range_, tags, relatedInfoList, DiagnosticSeverity::Information, errorCode, message_, des, + "default"); + + const auto &diagnosticTags = diagnostic.tags_; + EXPECT_EQ(diagnosticTags.size(), 1); + EXPECT_EQ(diagnosticTags[0], DiagnosticTag::Unnecessary); + + const auto &relatedInformation = diagnostic.relatedInformation_; + EXPECT_EQ(relatedInformation.size(), 1); + EXPECT_EQ(relatedInformation[0].message_, "Related information message"); +} + +TEST_F(LSPAPITests, DiagnosticDataField) +{ + int const dataValue = 42; + std::variant data = dataValue; + int const errorCode = 400; + int const dataResult = 42; + std::vector tags {}; + std::vector relatedInfoList {}; + + Diagnostic diagnostic(range_, tags, relatedInfoList, DiagnosticSeverity::Error, errorCode, message_, {}, {}, data); + + const auto &diagnosticData = diagnostic.data_; + EXPECT_EQ(std::get(diagnosticData), dataResult); +} + +TEST_F(LSPAPITests, CreateDiagnosticForNode1) +{ + using ark::es2panda::ir::AstNode; + using ark::es2panda::public_lib::Context; + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("file1.ets", ES2PANDA_STATE_CHECKED, "function main() {}"); + auto astNode = GetAstFromContext(ctx); + int const dataValue = 42; + std::variant data = dataValue; + int const errorCode = 400; + std::string message = "Diagnostic"; + std::vector tags {}; + std::vector relatedInfoList {}; + + Diagnostic diagnostic(range_, tags, relatedInfoList, DiagnosticSeverity::Error, errorCode, message, {}, {}, data); + FileDiagnostic result = ark::es2panda::lsp::CreateDiagnosticForNode(astNode, diagnostic); + + int const startLine = 0; + int const endLine = 0; + int const startChar = 0; + int const endChar = 18; + ASSERT_EQ(result.diagnostic.message_, "Diagnostic"); + ASSERT_EQ(result.diagnostic.range_.start.line_, startLine); + ASSERT_EQ(result.diagnostic.range_.end.line_, endLine); + ASSERT_EQ(result.diagnostic.range_.start.character_, startChar); + ASSERT_EQ(result.diagnostic.range_.end.character_, endChar); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, CreateDiagnosticForNode2) +{ + using ark::es2panda::ir::AstNode; + using ark::es2panda::public_lib::Context; + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("file1.ets", ES2PANDA_STATE_CHECKED, "function main() {}"); + auto astNode = GetAstFromContext(ctx); + int const dataValue = 42; + std::variant data = dataValue; + int const errorCode = 400; + std::string message = "Diagnostic {0}, for the {1}, and {2}"; + std::vector args = {"Error1", "Error2", "Error3"}; + std::vector tags {}; + std::vector relatedInfoList {}; + + Diagnostic diagnostic(range_, tags, relatedInfoList, DiagnosticSeverity::Error, errorCode, message, {}, {}, data); + FileDiagnostic result = ark::es2panda::lsp::CreateDiagnosticForNode(astNode, diagnostic, args); + + int const startLine = 0; + int const endLine = 0; + int const startChar = 0; + int const endChar = 18; + ASSERT_EQ(result.diagnostic.message_, "Diagnostic Error1, for the Error2, and Error3"); + ASSERT_EQ(result.diagnostic.range_.start.line_, startLine); + ASSERT_EQ(result.diagnostic.range_.end.line_, endLine); + ASSERT_EQ(result.diagnostic.range_.start.character_, startChar); + ASSERT_EQ(result.diagnostic.range_.end.character_, endChar); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, CreateDiagnosticForNode3) +{ + using ark::es2panda::ir::AstNode; + using ark::es2panda::public_lib::Context; + Initializer initializer = Initializer(); + es2panda_Context *ctx = + initializer.CreateContext("file1.ets", ES2PANDA_STATE_CHECKED, "let a = () => {\n return 1;\n}"); + auto astNode = reinterpret_cast(GetAstFromContext(ctx)); + astNode = astNode->FindChild([](ark::es2panda::ir::AstNode *child) { return child->IsArrowFunctionExpression(); }); + int const dataValue = 42; + std::variant data = dataValue; + int const errorCode = 400; + std::string message = "Diagnostic {0}, for the {1}, and {2}"; + std::vector args = {"Error1", "Error2", "Error3"}; + std::vector tags {}; + std::vector relatedInfoList {}; + + Diagnostic diagnostic(range_, tags, relatedInfoList, DiagnosticSeverity::Error, errorCode, message, {}, {}, data); + FileDiagnostic result = + ark::es2panda::lsp::CreateDiagnosticForNode(reinterpret_cast(astNode), diagnostic, args); + + int const startLine = 0; + int const endLine = 2; + int const startChar = 12; + int const endChar = 33; + ASSERT_EQ(result.diagnostic.message_, "Diagnostic Error1, for the Error2, and Error3"); + ASSERT_EQ(result.diagnostic.range_.start.line_, startLine); + ASSERT_EQ(result.diagnostic.range_.end.line_, endLine); + ASSERT_EQ(result.diagnostic.range_.start.character_, startChar); + ASSERT_EQ(result.diagnostic.range_.end.character_, endChar); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetFileReferencesImpl1) +{ + using ark::es2panda::public_lib::Context; + std::vector files = {"lsp_api_test_export_1.ets", "lsp_api_test_file_1.ets"}; + std::vector texts = { + R"(export function A(a:number, b:number): number { + return a + b; +} +export function B(a:number, b:number): number { + return a + b; +})", + R"(import {A} from "./lsp_api_test_export_1"; +import {B} from "./lsp_api_test_export_1.ets"; +A(1, 2); +B(1, 2);)"}; + auto filePaths = CreateTempFile(files, texts); + int const expectedFileCount = 2; + ASSERT_EQ(filePaths.size(), expectedFileCount); + + char const *searchFileName = filePaths[0].c_str(); + char const *referenceFileName = filePaths[1].c_str(); + Initializer initializer = Initializer(); + auto ctx = initializer.CreateContext(searchFileName, ES2PANDA_STATE_CHECKED); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + + auto isPackageModule = reinterpret_cast(ctx)->parserProgram->IsPackage(); + ASSERT_FALSE(isPackageModule); + initializer.DestroyContext(ctx); + + auto ctx1 = initializer.CreateContext(referenceFileName, ES2PANDA_STATE_CHECKED); + ASSERT_EQ(ContextState(ctx1), ES2PANDA_STATE_CHECKED); + + auto result = References(); + result = ark::es2panda::lsp::GetFileReferencesImpl(ctx1, searchFileName, isPackageModule); + auto expectedFileName1 = filePaths[1]; + size_t const expectedStartPos1 = 16; + size_t const expectedLength1 = 25; + auto expectedFileName2 = filePaths[1]; + size_t const expectedStartPos2 = 59; + size_t const expectedLength2 = 29; + ASSERT_EQ(result.referenceInfos.at(0).fileName, expectedFileName1); + ASSERT_EQ(result.referenceInfos.at(0).start, expectedStartPos1); + ASSERT_EQ(result.referenceInfos.at(0).length, expectedLength1); + ASSERT_EQ(result.referenceInfos.at(1).fileName, expectedFileName2); + ASSERT_EQ(result.referenceInfos.at(1).start, expectedStartPos2); + ASSERT_EQ(result.referenceInfos.at(1).length, expectedLength2); + initializer.DestroyContext(ctx1); +} + +TEST_F(LSPAPITests, GetFileReferencesImpl2) +{ + using ark::es2panda::public_lib::Context; + std::vector files = {"lsp_api_test_export_2.ts", "lsp_api_test_file_2.ets"}; + std::vector texts = { + R"(export function A(a:number, b:number): number { + return a + b; +} +export function B(a:number, b:number): number { + return a + b; +})", + R"(import {A} from "./lsp_api_test_export_2"; +import {B} from "./lsp_api_test_export_2.ts"; +A(1, 2); +B(1, 2);)"}; + auto filePaths = CreateTempFile(files, texts); + int const expectedFileCount = 2; + ASSERT_EQ(filePaths.size(), expectedFileCount); + + char const *searchFileName = filePaths[0].c_str(); + char const *referenceFileName = filePaths[1].c_str(); + Initializer initializer = Initializer(); + auto ctx = initializer.CreateContext(searchFileName, ES2PANDA_STATE_CHECKED); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + + auto isPackageModule = reinterpret_cast(ctx)->parserProgram->IsPackage(); + ASSERT_FALSE(isPackageModule); + initializer.DestroyContext(ctx); + + auto ctx1 = initializer.CreateContext(referenceFileName, ES2PANDA_STATE_CHECKED); + ASSERT_EQ(ContextState(ctx1), ES2PANDA_STATE_CHECKED); + + auto result = References(); + result = ark::es2panda::lsp::GetFileReferencesImpl(ctx1, searchFileName, isPackageModule); + auto expectedFileName1 = filePaths[1]; + size_t const expectedStartPos1 = 16; + size_t const expectedLength1 = 25; + auto expectedFileName2 = filePaths[1]; + size_t const expectedStartPos2 = 59; + size_t const expectedLength2 = 28; + ASSERT_EQ(result.referenceInfos.at(0).fileName, expectedFileName1); + ASSERT_EQ(result.referenceInfos.at(0).start, expectedStartPos1); + ASSERT_EQ(result.referenceInfos.at(0).length, expectedLength1); + ASSERT_EQ(result.referenceInfos.at(1).fileName, expectedFileName2); + ASSERT_EQ(result.referenceInfos.at(1).start, expectedStartPos2); + ASSERT_EQ(result.referenceInfos.at(1).length, expectedLength2); + initializer.DestroyContext(ctx1); +} + +TEST_F(LSPAPITests, GetFileReferencesImpl3) +{ + using ark::es2panda::public_lib::Context; + std::vector files = {"package-module.ets"}; + std::vector texts = {R"(import { PI } from "std/math"; +console.log(PI);)"}; + auto filePaths = CreateTempFile(files, texts); + int const expectedFileCount = 1; + ASSERT_EQ(filePaths.size(), expectedFileCount); + + char const *referenceFileName = filePaths[0].c_str(); + Initializer initializer = Initializer(); + auto ctx = initializer.CreateContext(referenceFileName, ES2PANDA_STATE_CHECKED); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + + auto baseUrl = reinterpret_cast(ctx)->config->options->ArkTSConfig()->BaseUrl(); + auto searchFileName = baseUrl + "/plugins/ets/stdlib/std/math/math.ets"; + auto result = References(); + result = ark::es2panda::lsp::GetFileReferencesImpl(ctx, searchFileName.c_str(), true); + auto expectedFileName = filePaths[0]; + size_t const expectedStartPos = 19; + size_t const expectedLength = 10; + + ASSERT_EQ(result.referenceInfos.at(0).fileName, expectedFileName); + ASSERT_EQ(result.referenceInfos.at(0).start, expectedStartPos); + ASSERT_EQ(result.referenceInfos.at(0).length, expectedLength); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetPrecedingToken1) +{ + using ark::es2panda::ir::AstNode; + + LSPAPI const *lspApi = GetImpl(); + Initializer initializer = Initializer(); + es2panda_Context *context = initializer.CreateContext( + + "precedingtoken_literal.ets", ES2PANDA_STATE_CHECKED, + "let number_literal: number = 1234;\nlet string_literal: string = \"hello\";\nconst str_property = " + "\"foo\";\n"); + ASSERT_EQ(ContextState(context), ES2PANDA_STATE_CHECKED); + auto ast = GetAstFromContext(context); + + size_t const numberLiteralOffset = 31; // 31: position of '3' in '1234' + size_t const stringLiteralOffset = 96; // 96: position of first 'o' in 'foo' + auto numberLiteral = ast->FindChild([](AstNode *node) { return node->IsExpressionStatement(); }) + ->AsExpressionStatement() + ->GetExpression() + ->AsAssignmentExpression() + ->Right() + ->AsNumberLiteral(); + auto result = reinterpret_cast(lspApi->getPrecedingToken(context, numberLiteralOffset)); + ASSERT_EQ(result->DumpJSON(), numberLiteral->DumpJSON()); + ASSERT_EQ(result->Start().index, numberLiteral->Start().index); + ASSERT_EQ(result->End().index, numberLiteral->End().index); + auto stringLiteral = ast->FindChild( + [](AstNode *node) { return node->IsStringLiteral() && node->AsStringLiteral()->ToString() == "foo"; }); + result = reinterpret_cast(lspApi->getPrecedingToken(context, stringLiteralOffset)); + ASSERT_EQ(result->DumpJSON(), stringLiteral->DumpJSON()); + ASSERT_EQ(result->Start().index, stringLiteral->Start().index); + ASSERT_EQ(result->End().index, stringLiteral->End().index); + initializer.DestroyContext(context); +} + +TEST_F(LSPAPITests, GetPrecedingToken2) +{ + using ark::es2panda::ir::AstNode; + + LSPAPI const *lspApi = GetImpl(); + Initializer initializer = Initializer(); + es2panda_Context *context = initializer.CreateContext( + "precedingtoken_function.ets", ES2PANDA_STATE_CHECKED, + " \n\n\n\nfunction f() {\n le\n let a = 123;\n}\n\n\n\nconst s = \"hello\";\n\n\n"); + auto ast = GetAstFromContext(context); + + size_t const startOfFile = 0; // 0: position of start of file + size_t const secondSpaceBeforeLe = 25; // 25: position of second space before 'le' + size_t const endOfLe = 29; // 29: position of the end of 'le' identifier + size_t const secondSpaceBeforeLet = 32; // 32: position of second space before 'let' + size_t const startOfLine10 = 50; // 50: position of start of line 10 + size_t const startOfLine14 = 72; // 72: position of start of line 14 + ASSERT_EQ(lspApi->getPrecedingToken(context, startOfFile), nullptr); + ASSERT_EQ(lspApi->getPrecedingToken(context, secondSpaceBeforeLe), nullptr); + auto leIdentifier = + ast->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "le"; }); + auto result = reinterpret_cast(lspApi->getPrecedingToken(context, endOfLe)); + ASSERT_EQ(result->DumpJSON(), leIdentifier->DumpJSON()); + ASSERT_EQ(result->Start().index, leIdentifier->Start().index); + ASSERT_EQ(result->End().index, leIdentifier->End().index); + result = reinterpret_cast(lspApi->getPrecedingToken(context, secondSpaceBeforeLet)); + ASSERT_EQ(result->DumpJSON(), leIdentifier->DumpJSON()); + ASSERT_EQ(result->Start().index, leIdentifier->Start().index); + ASSERT_EQ(result->End().index, leIdentifier->End().index); + auto numberLiteral = ast->FindChild( + [](AstNode *node) { return node->IsNumberLiteral() && node->AsNumberLiteral()->Str() == "123"; }); + result = reinterpret_cast(lspApi->getPrecedingToken(context, startOfLine10)); + ASSERT_EQ(result->DumpJSON(), numberLiteral->DumpJSON()); + ASSERT_EQ(result->Start().index, numberLiteral->Start().index); + ASSERT_EQ(result->End().index, numberLiteral->End().index); + auto stringLiteral = ast->FindChild([](AstNode *node) { return node->IsClassProperty(); }) + ->AsClassProperty() + ->Value() + ->AsStringLiteral(); + result = reinterpret_cast(lspApi->getPrecedingToken(context, startOfLine14)); + ASSERT_EQ(result->DumpJSON(), stringLiteral->DumpJSON()); + ASSERT_EQ(result->Start().index, stringLiteral->Start().index); + ASSERT_EQ(result->End().index, stringLiteral->End().index); + initializer.DestroyContext(context); +} + +TEST_F(LSPAPITests, GetTypeOfSymbolAtLocation1) +{ + using ark::es2panda::ir::AstNode; + using ark::es2panda::public_lib::Context; + Initializer initializer = Initializer(); + es2panda_Context *ctx = + initializer.CreateContext("types.ets", ES2PANDA_STATE_CHECKED, + "let a: number;\nlet b: byte;\nlet c: short;\nlet d: int;\nlet e: long;\nlet f: " + "float;\nlet g: double;\nlet h: char;\nlet i: boolean;"); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + + auto checker = reinterpret_cast(ctx)->GetChecker()->AsETSChecker(); + auto astNode = GetAstFromContext(ctx); + auto targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "a"; }); + auto type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsDoubleType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "b"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsByteType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "c"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsShortType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "d"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsIntType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "e"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsLongType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "f"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsFloatType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "g"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsDoubleType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "h"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsCharType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "i"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsETSBooleanType()); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetTypeOfSymbolAtLocation2) +{ + using ark::es2panda::ir::AstNode; + using ark::es2panda::public_lib::Context; + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext( + "types.ets", ES2PANDA_STATE_CHECKED, + "let j: object;\nlet k: string;\nlet l: [];\nlet m: bigint;\nlet n: never;\nlet o: null;\nlet p: " + "undefined;\nlet tuple: [number, number] = [1, 2];\nlet union: int | null;"); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + + auto checker = reinterpret_cast(ctx)->GetChecker()->AsETSChecker(); + auto astNode = GetAstFromContext(ctx); + auto targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "j"; }); + auto type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsETSObjectType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "k"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsETSStringType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "l"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsETSTupleType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "m"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsETSBigIntType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "n"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsETSNeverType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "o"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsETSNullType()); + + targetNode = + astNode->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "p"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsETSUndefinedType()); + + targetNode = astNode->FindChild( + [](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "tuple"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsETSTupleType()); + + targetNode = astNode->FindChild( + [](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "union"; }); + type = ark::es2panda::lsp::GetTypeOfSymbolAtLocation(checker, targetNode); + ASSERT_TRUE(type->IsETSUnionType()); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetCurrentTokenValue) +{ + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("current_token.ets", ES2PANDA_STATE_CHECKED, "ab"); + LSPAPI const *lspApi = GetImpl(); + size_t offset = 2; + std::string result = lspApi->getCurrentTokenValue(ctx, offset); + initializer.DestroyContext(ctx); + ASSERT_EQ(result, "ab"); +} + +TEST_F(LSPAPITests, GetCurrentTokenValue1) +{ + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("file1.ets", ES2PANDA_STATE_CHECKED, "\"ab\""); + size_t offset = 3; + std::string result = ark::es2panda::lsp::GetCurrentTokenValueImpl(ctx, offset); + std::string expect = "ab"; + ASSERT_EQ(result, expect); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetCurrentTokenValue2) +{ + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("file1.ets", ES2PANDA_STATE_CHECKED, "\'ab\'"); + size_t offset = 3; + std::string result = ark::es2panda::lsp::GetCurrentTokenValueImpl(ctx, offset); + std::string expect = "ab"; + ASSERT_EQ(result, expect); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetCurrentTokenValue3) +{ + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("file1.ets", ES2PANDA_STATE_CHECKED, "abc"); + size_t offset = 2; + std::string result = ark::es2panda::lsp::GetCurrentTokenValueImpl(ctx, offset); + std::string expect = "ab"; + ASSERT_EQ(result, expect); + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetTokenPosOfNode1) +{ + using ark::es2panda::ir::AstNode; + + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("token-pos-identifier.ets", ES2PANDA_STATE_CHECKED, + "function A(a:number, b:number) {\n return a + b;\n}\nA(1, 2);"); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + + auto ast = GetAstFromContext(ctx); + auto targetNode = + ast->FindChild([](AstNode *node) { return node->IsIdentifier() && node->AsIdentifier()->Name() == "A"; }); + + ASSERT_NE(targetNode, nullptr); + auto result = ark::es2panda::lsp::GetTokenPosOfNode(targetNode); + size_t const pos = 51; + ASSERT_EQ(result, pos); + + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetTokenPosOfNode2) +{ + using ark::es2panda::ir::AstNode; + + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext("token-pos-expression.ets", ES2PANDA_STATE_CHECKED, + "function A(a:number, b:number) {\n return a + b;\n}\nA(1, 2);"); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + + auto ast = GetAstFromContext(ctx); + auto targetNode = ast->FindChild([](AstNode *node) { return node->IsExpressionStatement(); }); + + ASSERT_NE(targetNode, nullptr); + auto result = ark::es2panda::lsp::GetTokenPosOfNode(targetNode); + size_t const pos = 51; + ASSERT_EQ(result, pos); + + initializer.DestroyContext(ctx); +} + +TEST_F(LSPAPITests, GetTokenPosOfNode3) +{ + using ark::es2panda::ir::AstNode; + + Initializer initializer = Initializer(); + es2panda_Context *ctx = initializer.CreateContext( + "token-pos-literal.ets", ES2PANDA_STATE_CHECKED, + "let number_literal: number = 1234;\nlet string_literal: string = \"hello\";\nconst str_property = " + "\"foo\";\n"); + ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); + + auto ast = GetAstFromContext(ctx); + auto targetNode = ast->FindChild( + [](AstNode *node) { return node->IsNumberLiteral() && node->AsNumberLiteral()->Str() == "1234"; }); + + ASSERT_NE(targetNode, nullptr); + auto result = ark::es2panda::lsp::GetTokenPosOfNode(targetNode); + size_t const pos = 29; + ASSERT_EQ(result, pos); + + initializer.DestroyContext(ctx); +} diff --git a/ets2panda/test/unit/lsp/lsp_rename_test.cpp b/ets2panda/test/unit/lsp/lsp_rename_test.cpp index ea1af27659e22815bacc7be14489e5eb31b38aca..39ad9d38870fac53c5e9301794ffaf4090bc5902 100644 --- a/ets2panda/test/unit/lsp/lsp_rename_test.cpp +++ b/ets2panda/test/unit/lsp/lsp_rename_test.cpp @@ -441,7 +441,7 @@ TEST_F(LspRenameInfoTests, RenameInfoGetRenameInfoForNode1) ASSERT_EQ(ContextState(ctx), ES2PANDA_STATE_CHECKED); auto ast = GetAstFromContext(ctx); - auto checker = reinterpret_cast(ctx)->checker->AsETSChecker(); + auto checker = reinterpret_cast(ctx)->GetChecker()->AsETSChecker(); auto program = reinterpret_cast(ctx)->parserProgram; auto targetNode = ast->FindChild([](ark::es2panda::ir::AstNode *node) { diff --git a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_i.cpp b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_i.cpp index 35f7374b7b19ba0bdd94fc171e5425d610a6af4c..7e88eff58069a34f01ac3ba0abc2ed237d37e9c3 100644 --- a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_i.cpp +++ b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_i.cpp @@ -343,7 +343,7 @@ TEST_F(PluginConversionRuleUnitTest, PairReturnValue) es2panda_Type *classInstance, [[maybe_unused]] es2panda_Type *sourceType/*return_args:*/, es2panda_Type **returnTypeSecond) { - auto *checkerE2p = reinterpret_cast(context)->checker->AsETSChecker(); + auto *checkerE2p = reinterpret_cast(context)->GetChecker()->AsETSChecker(); auto *sourceTypeE2p = reinterpret_cast(sourceType); auto *ctx = reinterpret_cast(context); [[maybe_unused]] auto *ctxAllocator = ctx->allocator; diff --git a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_ii.cpp b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_ii.cpp index d6f9e1b2820481ee809bf898384cd9ffa1f7d503..eee97381aa92785d2a7f9622fdb8c9bff839ce26 100644 --- a/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_ii.cpp +++ b/ets2panda/test/unit/plugin_conversion_rule/plugin_conversion_rule_part_ii.cpp @@ -60,7 +60,7 @@ TEST_F(PluginConversionRuleUnitTest, CheckerTypeRelationConstructor) std::string targetCAPI {R"( extern "C" es2panda_TypeRelation *CreateTypeRelation([[maybe_unused]] es2panda_Context *context) { - auto *checkerE2p = reinterpret_cast(context)->checker; + auto *checkerE2p = reinterpret_cast(context)->GetChecker(); auto *ctx = reinterpret_cast(context); auto *ctxAllocator = ctx->allocator; return reinterpret_cast(ctxAllocator->New(checkerE2p)); 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 8eb1282e8cd57206baca8071d10c9004b14e86fc..ca0bdcf046ed038577ebf40896cd06c95f31de5e 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 @@ -62,7 +62,7 @@ TEST_F(PluginConversionRuleUnitTest, CheckerContextPtrReturnValue) extern "C" es2panda_CheckerContext *CreateCheckerContext([[maybe_unused]] es2panda_Context *context, [[maybe_unused]] Es2pandaCheckerStatus newStatus) { - auto *checkerE2p = reinterpret_cast(context)->checker; + auto *checkerE2p = reinterpret_cast(context)->GetChecker(); auto newStatusE2p = E2pToIrCheckerStatus(newStatus); auto *ctx = reinterpret_cast(context); auto *ctxAllocator = ctx->allocator; @@ -97,7 +97,7 @@ TEST_F(PluginConversionRuleUnitTest, CheckerContextPtrConstructor) extern "C" es2panda_CheckerContext *CreateCheckerContext([[maybe_unused]] es2panda_Context *context, [[maybe_unused]] Es2pandaCheckerStatus newStatus) { - auto *checkerE2p = reinterpret_cast(context)->checker; + auto *checkerE2p = reinterpret_cast(context)->GetChecker(); auto newStatusE2p = E2pToIrCheckerStatus(newStatus); auto *ctx = reinterpret_cast(context); auto *ctxAllocator = ctx->allocator; @@ -352,7 +352,7 @@ TEST_F(PluginConversionRuleUnitTest, PropertyProcessorInputParameter) extern "C" void ETSObjectTypeUpdateTypeProperties([[maybe_unused]] es2panda_Context *context, es2panda_Type *classInstance, [[maybe_unused]] PropertyProcessor func/*return_args:*/) { - auto *checkerE2p = reinterpret_cast(context)->checker->AsETSChecker(); + auto *checkerE2p = reinterpret_cast(context)->GetChecker()->AsETSChecker(); std::function funcE2p = [func](varbinder::LocalVariable *propertyProcessorLambdaVariable, checker::Type *propertyProcessorLambdaType) { return reinterpret_cast(func(reinterpret_cast diff --git a/ets2panda/test/unit/union_normalisation_test.h b/ets2panda/test/unit/union_normalisation_test.h index 0a7312aa666b947aa427c947d87dfdc2a9789320..db0c7d60f88895a913a9bbda1c60ced5f51d8c7a 100644 --- a/ets2panda/test/unit/union_normalisation_test.h +++ b/ets2panda/test/unit/union_normalisation_test.h @@ -111,8 +111,8 @@ public: publicContext_->sourceFile = &unit.input; publicContext_->allocator = allocator_.get(); publicContext_->parser = &parser; - publicContext_->checker = checker; - publicContext_->analyzer = publicContext_->checker->GetAnalyzer(); + publicContext_->PushChecker(checker); + publicContext_->PushAnalyzer(publicContext_->GetChecker()->GetAnalyzer()); publicContext_->emitter = &emitter; publicContext_->parserProgram = program; publicContext_->diagnosticEngine = &diagnosticEngine_; diff --git a/ets2panda/test/utils/ast_verifier_test.h b/ets2panda/test/utils/ast_verifier_test.h index 68ccb22ecb1b9769f01705ae9a8c2fbcbfbff1bc..62d1612c82ab2bb70cf9be6908a3a47b90d6fe79 100644 --- a/ets2panda/test/utils/ast_verifier_test.h +++ b/ets2panda/test/utils/ast_verifier_test.h @@ -51,7 +51,7 @@ public: auto *GetChecker() { - return reinterpret_cast(ctx_)->checker->AsETSChecker(); + return reinterpret_cast(ctx_)->GetChecker()->AsETSChecker(); } auto *GetAst() diff --git a/ets2panda/test/utils/checker_test.h b/ets2panda/test/utils/checker_test.h index cd41db0d661cbc2f25eb74df4f8e162ea795bbcb..0f9ec9e91d29151b388ca96d51a2e92a4f46d012 100644 --- a/ets2panda/test/utils/checker_test.h +++ b/ets2panda/test/utils/checker_test.h @@ -118,8 +118,8 @@ public: publicContext_->sourceFile = &unit.input; publicContext_->allocator = allocator_.get(); publicContext_->parser = &parser; - publicContext_->checker = checker; - publicContext_->analyzer = publicContext_->checker->GetAnalyzer(); + publicContext_->PushChecker(checker); + publicContext_->PushAnalyzer(publicContext_->GetChecker()->GetAnalyzer()); publicContext_->emitter = &emitter; publicContext_->parserProgram = program; publicContext_->diagnosticEngine = &diagnosticEngine_; diff --git a/ets2panda/test/utils/scope_init_test.h b/ets2panda/test/utils/scope_init_test.h index ce8df944bac418aedcb6a0ded16ce672310dec65..949e31eb93afc94f2325a07f1fcda5a42bc24695 100644 --- a/ets2panda/test/utils/scope_init_test.h +++ b/ets2panda/test/utils/scope_init_test.h @@ -21,6 +21,7 @@ #include "ir/statements/variableDeclarator.h" #include "ir/statements/variableDeclaration.h" #include "mem/pool_manager.h" +#include "compiler/lowering/phase.h" #include @@ -30,7 +31,12 @@ namespace test::utils { class ScopeInitTest : public testing::Test { public: - ScopeInitTest() : allocator_(std::make_unique(ark::SpaceType::SPACE_TYPE_COMPILER)) {} + ScopeInitTest() : allocator_(std::make_unique(ark::SpaceType::SPACE_TYPE_COMPILER)) + { + phaseManager_ = std::make_unique(ark::es2panda::ScriptExtension::ETS, + allocator_.get()); + ark::es2panda::compiler::SetPhaseManager(phaseManager_.get()); + } /* * Shortcut to convert single elemnt block expression body to it's name @@ -51,6 +57,7 @@ public: private: std::unique_ptr allocator_; + std::unique_ptr phaseManager_; }; } // namespace test::utils diff --git a/ets2panda/util/diagnosticEngine.h b/ets2panda/util/diagnosticEngine.h index 0562a1cb453f1188dd5d0c7973e034f99b1ae7d5..6f795e15e762a4b736d594866e9c189b9b50d088 100644 --- a/ets2panda/util/diagnosticEngine.h +++ b/ets2panda/util/diagnosticEngine.h @@ -79,6 +79,13 @@ public: LogDiagnostic(std::forward(args)...); } + void ClearDiagnostics() + { + for (auto &it : diagnostics_) { + it.clear(); + } + } + // NOTE(schernykh): should be removed void Log([[maybe_unused]] const ThrowableDiagnostic &error) { diff --git a/ets2panda/util/enumbitops.h b/ets2panda/util/enumbitops.h index 46a95feeb13deec32a36e70db739689d02203b04..b22f3325b19332835b92a5e03e3faea22018be79 100644 --- a/ets2panda/util/enumbitops.h +++ b/ets2panda/util/enumbitops.h @@ -27,7 +27,9 @@ enumbitops::operator^, \ enumbitops::operator|=, \ enumbitops::operator&=, \ - enumbitops::operator^= + enumbitops::operator^=, \ + enumbitops::All, \ + enumbitops::Any // clang-format on namespace enumbitops { @@ -98,6 +100,20 @@ inline constexpr T &operator^=(T &a, T b) return a = a ^ b; } +template ::value, bool> = true> +inline constexpr bool All(T flags, T test) +{ + using Utype = std::underlying_type_t; + return (flags & test) == static_cast(test); +} + +template ::value, bool> = true> +inline constexpr bool Any(T flags, T test) +{ + using Utype = std::underlying_type_t; + return (flags & test) != static_cast(0); +} + } // namespace enumbitops #endif diff --git a/ets2panda/util/es2pandaMacros.h b/ets2panda/util/es2pandaMacros.h index cc0990c7b5768973d1159ca7af31193b5bcfa31d..44a00d909da6c415dedf058bd3a5a7e7dff52424 100644 --- a/ets2panda/util/es2pandaMacros.h +++ b/ets2panda/util/es2pandaMacros.h @@ -18,6 +18,144 @@ #include "macros.h" #include "lexer/token/sourceLocation.h" + +inline constexpr std::string_view const SET_CHILD_RECURSIVE = "SetChildRecursive"; +// #define CHANGEABLE_SET_CHILD(NodeName) +// if (NodeName != this) { +// auto thisNode = this; +// auto parent = this->GetOrCreateHistoryNodeParent(); +// if (parent != nullptr) { +// parent->TransformChildren( +// [&](AstNode *node) -> AstNode * { +// if (node == thisNode) { +// NodeName->SetParent(parent); +// return NodeName; +// } +// return node; +// }, +// SET_CHILD_RECURSIVE); +// } +// } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHANGEABLE_SET_CHILD(NodeName) ; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SETTER_FOR_CHILD_BODY(TypeName, Source, TargetElementName) \ + auto newNode = reinterpret_cast(GetOrCreateHistoryNode()); \ + CHANGEABLE_SET_CHILD(newNode); \ + newNode->TargetElementName = Source + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SETTER_FOR_CHILD(TypeName, SourceElementName, TargetElementName, ElementType) \ + void TypeName::Set##SourceElementName(ElementType source) \ + { \ + SETTER_FOR_CHILD_BODY(TypeName, source, TargetElementName); \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SETTER_FOR_FIELD(TypeName, SourceElementName, TargetElementName, ElementType) \ + void TypeName::Set##SourceElementName(ElementType source) \ + { \ + reinterpret_cast(GetOrCreateHistoryNode())->TargetElementName = source; \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SETTER_FOR_CHILD_REF(TypeName, SourceElementName, TargetElementName, ElementType) \ + [[nodiscard]] ElementType &TypeName::SourceElementName() \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + CHANGEABLE_SET_CHILD(newNode); \ + return newNode->TargetElementName; \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define RETURN_GET(TypeName, Property) return reinterpret_cast(GetHistoryNode())->Property; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SETTER_FOR_ARENAVECTOR_CHILD(TypeName, SourceElementName, TargetElementName, VectorElementType) \ + void TypeName::Emplace##SourceElementName(VectorElementType source) \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + CHANGEABLE_SET_CHILD(newNode); \ + newNode->TargetElementName.emplace_back(source); \ + } \ + void TypeName::Clear##SourceElementName() \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + CHANGEABLE_SET_CHILD(newNode); \ + newNode->TargetElementName.clear(); \ + } \ + void TypeName::SetValue##SourceElementName(VectorElementType source, size_t index) \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + CHANGEABLE_SET_CHILD(newNode); \ + auto &arenaVector = newNode->TargetElementName; \ + ES2PANDA_ASSERT(arenaVector.size() > index); \ + arenaVector[index] = source; \ + } \ + SETTER_FOR_CHILD_REF(TypeName, SourceElementName, TargetElementName, ArenaVector) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SETTER_FOR_ARENASET_FIELD(TypeName, SourceElementName, TargetElementName, VectorElementType) \ + bool TypeName::Insert##SourceElementName(VectorElementType source) \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + return newNode->TargetElementName.insert(source).second; \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SETTER_FOR_ARENASET_CHILD(TypeName, SourceElementName, TargetElementName, VectorElementType) \ + bool TypeName::Insert##SourceElementName(VectorElementType source) \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + CHANGEABLE_SET_CHILD(newNode); \ + return newNode->TargetElementName.insert(source).second; \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SETTER_FOR_ARENAVECTOR_FIELD(TypeName, SourceElementName, TargetElementName, VectorElementType) \ + void TypeName::Emplace##SourceElementName(VectorElementType source) \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + newNode->TargetElementName.emplace_back(source); \ + } \ + void TypeName::Clear##SourceElementName() \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + newNode->TargetElementName.clear(); \ + } \ + void TypeName::SetValue##SourceElementName(VectorElementType source, size_t index) \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + auto &arenaVector = newNode->TargetElementName; \ + ES2PANDA_ASSERT(arenaVector.size() > index); \ + arenaVector[index] = source; \ + } \ + [[nodiscard]] ArenaVector &TypeName::SourceElementName() \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + CHANGEABLE_SET_CHILD(newNode); \ + return newNode->TargetElementName; \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SETTER_FOR_ARENASET_FIELD(TypeName, SourceElementName, TargetElementName, VectorElementType) \ + bool TypeName::Insert##SourceElementName(VectorElementType source) \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + return newNode->TargetElementName.insert(source).second; \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SETTER_FOR_ARENASET_CHILD(TypeName, SourceElementName, TargetElementName, VectorElementType) \ + bool TypeName::Insert##SourceElementName(VectorElementType source) \ + { \ + auto newNode = reinterpret_cast(this->GetOrCreateHistoryNode()); \ + CHANGEABLE_SET_CHILD(newNode); \ + return newNode->TargetElementName.insert(source).second; \ + } + namespace ark::es2panda::parser { class Program; } // namespace ark::es2panda::parser diff --git a/ets2panda/util/importPathManager.cpp b/ets2panda/util/importPathManager.cpp index 9475b2b7bba728ae7e4f6776c6bdcfd718af1fc7..2cfb4e3533038e5500ac4594e2a26e0d0067738b 100644 --- a/ets2panda/util/importPathManager.cpp +++ b/ets2panda/util/importPathManager.cpp @@ -74,6 +74,13 @@ ImportPathManager::ImportMetadata ImportPathManager::GatherImportMetadata(parser return ImportMetadata {util::ImportFlags::NONE, Language::Id::COUNT, ERROR_LITERAL}; } + // std::cout << "global program in importPathManager: " << globalProgram_->AbsoluteName() << std::endl; + // std::cout << "ImportPathManager::GatherImportMetadata: " << "cur program path: " << curModulePath << " imported path: " << resolvedImportPath << std::endl; + + // TODO: use parse mode to control the collection + globalProgram_->AddFileDependencies(std::string(curModulePath), std::string(resolvedImportPath)); + globalProgram_->AddFileDependants(std::string(resolvedImportPath), std::string(curModulePath)); + ImportMetadata importData {importFlags}; importData.resolvedSource = resolvedImportPath; if (resolvedIsDynamic) { diff --git a/ets2panda/util/importPathManager.h b/ets2panda/util/importPathManager.h index 9e8a1e731683cca25b43c8885333de13194a3872..650a33b9d2ddf5c2835edfc6283735fab5036fb1 100644 --- a/ets2panda/util/importPathManager.h +++ b/ets2panda/util/importPathManager.h @@ -125,6 +125,11 @@ public: return parseList_; } + void ClearParseList() + { + parseList_.clear(); + } + util::StringView FormModuleName(const util::Path &path, const lexer::SourcePosition &srcPos); ImportMetadata GatherImportMetadata(parser::Program *program, ImportFlags importFlags, ir::StringLiteral *importPath); @@ -156,7 +161,8 @@ private: std::string TryMatchDynamicPath(std::string_view fixedPath) const; StringView GetRealPath(StringView path) const; - void AddToParseList(const ImportMetadata importMetadata); +public: + void AddToParseList(ImportMetadata importMetadata); #ifdef USE_UNIX_SYSCALL void UnixWalkThroughDirectoryAndAddToParseList(ImportMetadata importMetadata); #endif diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index 24cd0a38df6fb64065567b734fba4a7a907f2257..b2fae4438053b6e9863d624d52b11f6714a01cda 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -75,7 +75,7 @@ bool ETSBinder::HandleDynamicVariables(ir::Identifier *ident, Variable *variable bool ETSBinder::LookupInDebugInfoPlugin(ir::Identifier *ident) { - auto *checker = GetContext()->checker->AsETSChecker(); + auto *checker = GetContext()->GetChecker()->AsETSChecker(); auto *debugInfoPlugin = checker->GetDebugInfoPlugin(); if (UNLIKELY(debugInfoPlugin)) { auto *var = debugInfoPlugin->FindClass(ident); @@ -96,7 +96,7 @@ static void CreateDummyVariable(ETSBinder *varBinder, ir::Identifier *ident) varBinder->NewVarDecl(ident->Start(), compiler::GenName(varBinder->Allocator()).View()); var->SetScope(varBinder->GetScope()); ident->SetVariable(var); - ident->SetTsType(var->SetTsType(varBinder->GetContext()->checker->AsETSChecker()->GlobalTypeError())); + ident->SetTsType(var->SetTsType(varBinder->GetContext()->GetChecker()->AsETSChecker()->GlobalTypeError())); decl->BindNode(ident); } @@ -515,7 +515,7 @@ void ETSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *classDef) } } else { ES2PANDA_ASSERT(GetContext()->diagnosticEngine->IsAnyError()); - auto *checker = GetContext()->checker->AsETSChecker(); + auto *checker = GetContext()->GetChecker()->AsETSChecker(); prop->SetTsType(checker->GlobalTypeError()); prop->Id()->SetTsType(checker->GlobalTypeError()); } @@ -641,11 +641,13 @@ void AddOverloadFlag(ArenaAllocator *allocator, bool isStdLib, varbinder::Variab if (!currentNode->HasOverload(method)) { currentNode->AddOverload(method); - method->Function()->Id()->SetVariable(variable); - method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); - method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD); - util::UString newInternalName(method->Function()->Scope()->Name(), allocator); - method->Function()->Scope()->BindInternalName(newInternalName.View()); + if (method->Function()->Scope()->InternalName() == "") { + method->Function()->Id()->SetVariable(variable); + method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); + method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL_OVERLOAD); + util::UString newInternalName(method->Function()->Scope()->Name(), allocator); + method->Function()->Scope()->BindInternalName(newInternalName.View()); + } } } @@ -658,6 +660,9 @@ void ETSBinder::ImportAllForeignBindings(ir::AstNode *const specifier, bool const isStdLib = util::Helpers::IsStdLib(Program()); for (const auto [bindingName, var] : globalBindings) { + if (!var->Declaration()->Node()->IsValidInCurrentPhase()) { + continue; + } if (bindingName.Is(compiler::Signatures::ETS_GLOBAL)) { const auto *const classDef = var->Declaration()->Node()->AsClassDeclaration()->Definition(); ImportGlobalProperties(classDef); @@ -975,7 +980,10 @@ static Variable *FindInStatic(parser::Program *program) static Variable *FindInInstance(parser::Program *program) { - auto predicateFunc = [](const auto &item) { return item.second->Declaration()->Node()->IsDefaultExported(); }; + auto predicateFunc = [](const auto &item) { + return item.second->Declaration()->Node()->IsValidInCurrentPhase() && + item.second->Declaration()->Node()->IsDefaultExported(); + }; const auto &instanceMethodBindings = program->GlobalClassScope()->InstanceMethodScope()->Bindings(); auto result = std::find_if(instanceMethodBindings.begin(), instanceMethodBindings.end(), predicateFunc); if (result == instanceMethodBindings.end()) { @@ -1117,7 +1125,7 @@ bool ETSBinder::BuildInternalName(ir::ScriptFunction *scriptFunc) bool compilable = scriptFunc->Body() != nullptr && !isExternal; if (!compilable) { - recordTable_->Signatures().push_back(funcScope); + recordTable_->EmplaceSignatures(funcScope, scriptFunc); } return compilable; @@ -1140,7 +1148,7 @@ bool ETSBinder::BuildInternalNameWithCustomRecordTable(ir::ScriptFunction *const const bool compilable = scriptFunc->Body() != nullptr && !isExternal; if (!compilable) { - recordTable->Signatures().push_back(funcScope); + recordTable->EmplaceSignatures(funcScope, scriptFunc); } return compilable; @@ -1205,7 +1213,7 @@ void ETSBinder::BuildProgram() ValidateReexports(); - auto &stmts = Program()->Ast()->Statements(); + auto &stmts = Program()->Ast()->StatmentsForUpdates(); const auto etsGlobal = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) { if (stmt->IsClassDeclaration() && !stmt->AsClassDeclaration()->Definition()->Ident()->Name().Is(compiler::Signatures::ETS_GLOBAL)) { @@ -1238,13 +1246,19 @@ void ETSBinder::BuildExternalProgram(parser::Program *extProgram) auto flags = Program()->VarBinder()->IsGenStdLib() ? RecordTableFlags::NONE : RecordTableFlags::EXTERNAL; auto *extRecordTable = Allocator()->New(Allocator(), extProgram, flags); + extRecordTable->SetClassDefinition(extProgram->GlobalClass()); + externalRecordTable_.insert({extProgram, extRecordTable}); ResetTopScope(extProgram->GlobalScope()); recordTable_ = extRecordTable; SetProgram(extProgram); - BuildProgram(); + if (!extProgram->IsASTLowered()) { + BuildProgram(); + } else { + extRecordTable->Merge(extProgram->VarBinder()->AsETSBinder()->GetExternalRecordTable().at(extProgram)); + } SetProgram(savedProgram); recordTable_ = savedRecordTable; @@ -1336,7 +1350,7 @@ void ETSBinder::ValidateReexportDeclaration(ir::ETSReExportDeclaration *decl) const auto *const import = decl->GetETSImportDeclarations(); const auto &specifiers = import->Specifiers(); - for (auto specifier : specifiers) { + for (auto const specifier : specifiers) { // Example: export {foo} from "./A" if (specifier->IsImportSpecifier()) { auto importSpecifier = specifier->AsImportSpecifier(); diff --git a/ets2panda/varbinder/ETSBinder.h b/ets2panda/varbinder/ETSBinder.h index 6463ebb852c532f80f45ee31f5244a7144e466a0..95701c34163782e6920477e806946856f4e28540 100644 --- a/ets2panda/varbinder/ETSBinder.h +++ b/ets2panda/varbinder/ETSBinder.h @@ -57,7 +57,7 @@ using DynamicImportVariables = ArenaUnorderedMapAdapter()), @@ -74,7 +74,10 @@ public: ETSBinder() = delete; NO_COPY_SEMANTIC(ETSBinder); NO_MOVE_SEMANTIC(ETSBinder); - ~ETSBinder() override = default; + ~ETSBinder() override + { + delete Allocator(); + } [[nodiscard]] ScriptExtension Extension() const noexcept override { @@ -203,10 +206,15 @@ public: void AddReExportImport(ir::ETSReExportDeclaration *reExport) noexcept { - reExportImports_.push_back(reExport); + reExportImports_.insert(reExport); + } + + [[nodiscard]] const ArenaUnorderedSet &ReExportImports() const noexcept + { + return reExportImports_; } - [[nodiscard]] const ArenaVector &ReExportImports() const noexcept + [[nodiscard]] ArenaUnorderedSet &ReExportImports() noexcept { return reExportImports_; } @@ -267,6 +275,18 @@ public: globalRecordTable_.CleanUp(); } + void CopyTo(VarBinder *target) override + { + auto targetImpl = reinterpret_cast(target); + + targetImpl->defaultImports_ = defaultImports_; + InitImplicitThisParam(); + targetImpl->selectiveExportAliasMultimap_ = selectiveExportAliasMultimap_; + ; + + VarBinder::CopyTo(target); + } + private: void BuildClassDefinitionImpl(ir::ClassDefinition *classDef); void InitImplicitThisParam(); @@ -285,14 +305,14 @@ private: RecordTable globalRecordTable_; RecordTable *recordTable_; ArenaMap externalRecordTable_; - ArenaVector defaultImports_; + ArenaVector defaultImports_; // 1 ArenaVector dynamicImports_; - ArenaVector reExportImports_; + ArenaUnorderedSet reExportImports_; ArenaSet reexportedNames_; DynamicImportVariables dynamicImportVars_; - ir::Identifier *thisParam_ {}; + ir::Identifier *thisParam_ {}; // 2 ir::AstNode *defaultExport_ {}; - ModulesToExportedNamesWithAliases selectiveExportAliasMultimap_; + ModulesToExportedNamesWithAliases selectiveExportAliasMultimap_; // 3 friend class RecordTableContext; }; @@ -302,7 +322,8 @@ public: RecordTableContext(ETSBinder *varBinder, parser::Program *extProgram) : varBinder_(varBinder), savedRecordTable_(varBinder->recordTable_) { - if (extProgram != nullptr) { + if (extProgram != nullptr && + varBinder->externalRecordTable_.find(extProgram) != varBinder->externalRecordTable_.end()) { varBinder->recordTable_ = varBinder->externalRecordTable_[extProgram]; } } diff --git a/ets2panda/varbinder/recordTable.h b/ets2panda/varbinder/recordTable.h index 1b3c9bd10c98555613327fa05b3ac7b8e8f766a3..437a2ffb79dd259f21257e6901141194fc991930 100644 --- a/ets2panda/varbinder/recordTable.h +++ b/ets2panda/varbinder/recordTable.h @@ -21,6 +21,8 @@ #include "util/ustring.h" #include "util/enumbitops.h" +#include + namespace ark::es2panda::parser { class Program; } // namespace ark::es2panda::parser @@ -72,6 +74,25 @@ public: ~RecordTable() = default; + void Merge(RecordTable *other) + { + for (auto classDef : other->classDefinitions_) { + classDefinitions_.insert(classDef); + } + + for (auto interfaceDecl : other->InterfaceDeclarations()) { + interfaceDeclarations_.insert(interfaceDecl); + } + + for (auto annoDecl : other->AnnotationDeclarations()) { + annotationDeclarations_.insert(annoDecl); + } + + for (auto sig : other->signatures_) { + signatures_.insert(sig); + } + } + bool IsExternal() const { return (flags_ & RecordTableFlags::EXTERNAL) != 0; @@ -107,16 +128,22 @@ public: return annotationDeclarations_; } - ArenaVector &Signatures() + ArenaSet &Signatures() { return signatures_; } - const ArenaVector &Signatures() const + const ArenaSet &Signatures() const { return signatures_; } + void EmplaceSignatures(varbinder::FunctionScope *signature, ir::ScriptFunction *func) + { + func->AddFlag(ir::ScriptFunctionFlags::IN_RECORD); + signatures_.insert(signature); + } + void SetClassDefinition(ir::ClassDefinition *classDefinition) { record_ = classDefinition; @@ -208,7 +235,7 @@ private: ArenaSet classDefinitions_; ArenaSet interfaceDeclarations_; ArenaSet annotationDeclarations_; - ArenaVector signatures_; + ArenaSet signatures_; RecordHolder record_ {nullptr}; parser::Program *program_ {}; BoundContext *boundCtx_ {}; diff --git a/ets2panda/varbinder/varbinder.cpp b/ets2panda/varbinder/varbinder.cpp index 7d668b5de24eca46040b9fff9cfe3b07c09cc012..0cef33fa7fa13eb7574ffd3ca9e462de9cff420c 100644 --- a/ets2panda/varbinder/varbinder.cpp +++ b/ets2panda/varbinder/varbinder.cpp @@ -458,6 +458,19 @@ void VarBinder::VisitScriptFunction(ir::ScriptFunction *func) } if (!BuildInternalName(func)) { + if (func->Body() == nullptr) { + return; + } + auto stmt = func->Body()->AsBlockStatement()->Statements(); + auto scopeCtx = LexicalScope::Enter(this, funcScope); + std::function doNode = [&](ir::AstNode *node) { + if (node->IsTSInterfaceDeclaration() || node->IsClassDeclaration() || node->IsTSEnumDeclaration() || + node->IsAnnotationDeclaration()) { + ResolveReference(node); + } + node->Iterate([&](ir::AstNode *child) { doNode(child); }); + }; + doNode(func->Body()); return; } diff --git a/ets2panda/varbinder/varbinder.h b/ets2panda/varbinder/varbinder.h index 8fe135f211e4d84fa7e16760abc2fb9cd928a844..ff37ffbdfe9123c3162fd53bbef50f2e58a141a8 100644 --- a/ets2panda/varbinder/varbinder.h +++ b/ets2panda/varbinder/varbinder.h @@ -279,16 +279,25 @@ protected: functionScopes_.clear(); } + virtual void CopyTo(VarBinder *target) + { + target->program_ = program_; + target->allocator_ = allocator_; + target->context_ = context_; + target->bindingOptions_ = bindingOptions_; + target->genStdLib_ = genStdLib_; + } + private: - parser::Program *program_ {}; - ArenaAllocator *allocator_ {}; - public_lib::Context *context_ {}; + parser::Program *program_ {}; // 1 + ArenaAllocator *allocator_ {}; // 2 + public_lib::Context *context_ {}; // 3 GlobalScope *topScope_ {}; Scope *scope_ {}; VariableScope *varScope_ {}; ArenaVector functionScopes_; - ResolveBindingOptions bindingOptions_ {}; - bool genStdLib_ {false}; + ResolveBindingOptions bindingOptions_ {}; // 4 + bool genStdLib_ {false}; // 5 }; template diff --git a/ets2panda/varbinder/variable.h b/ets2panda/varbinder/variable.h index ba937f6b0135da8607f155b9bdd9cb9a045fae43..be95eb82d3fd27bc765b38cb42380c925f96502d 100644 --- a/ets2panda/varbinder/variable.h +++ b/ets2panda/varbinder/variable.h @@ -152,7 +152,7 @@ private: class LocalVariable : public Variable { public: explicit LocalVariable(Decl *decl, VariableFlags flags); - explicit LocalVariable(VariableFlags flags); + explicit LocalVariable(const VariableFlags flags); VariableType Type() const override { diff --git a/legacy_bin/api8/package-lock.json b/legacy_bin/api8/package-lock.json index 4f5ea9f21e876a0a4ed3f347dfd38175723fa7ba..692033ca26136fa246b449c7b08f9f759a4c99bb 100644 --- a/legacy_bin/api8/package-lock.json +++ b/legacy_bin/api8/package-lock.json @@ -8,6 +8,11 @@ "version": "9.4.0", "resolved": "https://repo.huaweicloud.com/repository/npm/commander/-/commander-9.4.0.tgz", "integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==" + }, + "typescript": { + "version": "4.2.3", + "resolved": "https://repo.huaweicloud.com/repository/npm/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==" } } } diff --git a/t->AsETSModule()->SetStatements(std::move(body)); b/t->AsETSModule()->SetStatements(std::move(body)); new file mode 100644 index 0000000000000000000000000000000000000000..0d132b46cf34330acee7edfce6b9293fe8fbe711 --- /dev/null +++ b/t->AsETSModule()->SetStatements(std::move(body)); @@ -0,0 +1,2247 @@ +diff --git a/ets2panda/checker/ets/dynamic.cpp b/ets2panda/checker/ets/dynamic.cpp +index 503cb2567..7c3d73cee 100644 +--- a/ets2panda/checker/ets/dynamic.cpp ++++ b/ets2panda/checker/ets/dynamic.cpp +@@ -360,7 +360,7 @@ ir::ClassDeclaration *ETSChecker::BuildClass(util::StringView name, const ClassB + // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + auto *classDecl = AllocNode(classDef, Allocator()); +  +- VarBinder()->Program()->Ast()->Statements().push_back(classDecl); ++ VarBinder()->Program()->Ast()->AddStatement(classDecl); + classDecl->SetParent(VarBinder()->Program()->Ast()); +  + varbinder::BoundContext boundCtx(VarBinder()->AsETSBinder()->GetGlobalRecordTable(), classDef); +@@ -577,7 +577,7 @@ void ETSChecker::EmitDynamicModuleClassInitCall() + // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + auto *const node = AllocNode(initCall); + node->SetParent(cctorBody); +- cctorBody->Statements().push_back(node); ++ cctorBody->AddStatement(node); +  + ProcessScopesNode(this, node); + ProcessCheckerNode(this, node); +diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp +index 69ed5cb22..93018094d 100644 +--- a/ets2panda/checker/ets/utilityTypeHandlers.cpp ++++ b/ets2panda/checker/ets/utilityTypeHandlers.cpp +@@ -591,7 +591,7 @@ ir::TSInterfaceDeclaration *ETSChecker::CreateInterfaceProto(util::StringView na +  + // Put class declaration in global scope, and in program AST + partialInterface->SetParent(interfaceDeclProgram->Ast()); +- interfaceDeclProgram->Ast()->Statements().push_back(partialInterface); ++ interfaceDeclProgram->Ast()->AddStatement(partialInterface); + interfaceDeclProgram->GlobalScope()->InsertBinding(name, var); +  + partialInterface->AddModifier(flags); +@@ -764,7 +764,7 @@ ir::ClassDefinition *ETSChecker::CreateClassPrototype(util::StringView name, par + decl->BindNode(classDef); +  + // Put class declaration in global scope, and in program AST +- classDeclProgram->Ast()->Statements().push_back(classDecl); ++ classDeclProgram->Ast()->AddStatement(classDecl); + classDeclProgram->GlobalScope()->InsertBinding(name, var); +  + return classDef; +diff --git a/ets2panda/compiler/core/CFG.cpp b/ets2panda/compiler/core/CFG.cpp +index cfafe5d79..2a8284e13 100644 +--- a/ets2panda/compiler/core/CFG.cpp ++++ b/ets2panda/compiler/core/CFG.cpp +@@ -324,6 +324,8 @@ CFG::BasicBlock *CFG::BuildETSExpressions(ir::AstNode *node, CFG::BasicBlock *bb +  + CFG::BasicBlock *CFG::BuildStatements(ir::AstNode *node, CFG::BasicBlock *bb) + { ++ // std::cout << "node=" << node << std::endl; ++ // std::cout << "type=" << (int)node->Type() << std::endl; + switch (node->Type()) { + case ir::AstNodeType::BLOCK_STATEMENT: + return Build(node->AsBlockStatement(), bb); +diff --git a/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp b/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp +index d9ede70dc..44c422f9f 100644 +--- a/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp ++++ b/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp +@@ -185,7 +185,7 @@ static void CreateFunctionOverload(ir::MethodDefinition *method, ArenaVectorSetRange(funcExpression->Range()); +  + if (!method->IsDeclare() && method->Parent()->IsTSInterfaceBody()) { +- overloadMethod->Function()->Body()->AsBlockStatement()->Statements().clear(); ++ overloadMethod->Function()->Body()->AsBlockStatement()->ClearStatements(); + } +  + method->AddOverload(overloadMethod); +diff --git a/ets2panda/compiler/lowering/ets/enumLowering.cpp b/ets2panda/compiler/lowering/ets/enumLowering.cpp +index bae3d9e96..572fdd1aa 100644 +--- a/ets2panda/compiler/lowering/ets/enumLowering.cpp ++++ b/ets2panda/compiler/lowering/ets/enumLowering.cpp +@@ -318,7 +318,7 @@ ir::ScriptFunction *EnumLoweringPhase::CreateFunctionForCtorOfEnumClass(ir::Clas + lexer::TokenType::PUNCTUATOR_SUBSTITUTION); + auto initStatement = checker_->AllocNode(initializer); + initStatement->SetParent(body); +- body->Statements().push_back(initStatement); ++ body->AddStatement(initStatement); +  + return func; + } +diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +index 7805edd43..ed6572acb 100644 +--- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp ++++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +@@ -790,7 +790,7 @@ static ir::ClassDeclaration *CreateEmptyLambdaClassDeclaration(public_lib::Conte + } +  + auto *program = varBinder->GetRecordTable()->Program(); +- program->Ast()->Statements().push_back(classDeclaration); ++ program->Ast()->AddStatement(classDeclaration); + classDeclaration->SetParent(program->Ast()); +  + return classDeclaration; +diff --git a/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp b/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp +index 0f1f93533..c2d70a2ad 100644 +--- a/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp ++++ b/ets2panda/compiler/lowering/ets/packageImplicitImport.cpp +@@ -32,7 +32,7 @@ static void MergeExternalFilesIntoCompiledProgram(parser::Program *const program +  + // Because same package files must be in one folder, relative path references in an external + // source's import declaration certainly will be the same (and can be resolved) from the global program too +- program->Ast()->Statements().emplace_back(stmt); ++ program->Ast()->AddStatement(stmt); + } + } + } +diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +index 1b8e60eca..c95bf1ae2 100644 +--- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp ++++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +@@ -126,11 +126,9 @@ void GlobalClassHandler::MergeNamespace(ArenaVector &namespaces + parser->LogError(diagnostic::NAMESPACE_ANNOTATION_CONFLICT, {ns->Ident()->Name().Mutf8()}, ns->Start()); + } else if (!ns->Annotations().empty()) { + ES2PANDA_ASSERT(res->second->Annotations().empty()); +- res->second->SetAnnotations(std::move(ns->Annotations())); +- } +- for (auto *statement : ns->Statements()) { +- res->second->Statements().emplace_back(statement); ++ res->second->SetAnnotations(ns->StealAnnotations()); + } ++ res->second->AddStatements(ns->Statements()); + namespaces.erase(it); + } else { + nsMap.insert({ns->Ident()->Name(), ns}); +@@ -139,10 +137,10 @@ void GlobalClassHandler::MergeNamespace(ArenaVector &namespaces + } + } +  +-ArenaVector GlobalClassHandler::TransformNamespaces(ArenaVector &namespaces, +- parser::Program *program) ++ArenaVector GlobalClassHandler::TransformNamespaces(ArenaVector &namespaces, ++ parser::Program *program) + { +- ArenaVector classDecls {allocator_->Adapter()}; ++ ArenaVector classDecls {allocator_->Adapter()}; + MergeNamespace(namespaces, program); + for (auto ns : namespaces) { + classDecls.emplace_back(TransformNamespace(ns, program)); +@@ -199,8 +197,8 @@ ir::ClassDeclaration *GlobalClassHandler::TransformNamespace(ir::ETSModule *ns, + void GlobalClassHandler::CollectProgramGlobalClasses(parser::Program *program, ArenaVector namespaces) + { + auto classDecls = TransformNamespaces(namespaces, program); ++ program->Ast()->AddStatements(classDecls); + for (auto cls : classDecls) { +- program->Ast()->Statements().push_back(cls); + cls->SetParent(program->Ast()); + } + } +@@ -216,7 +214,7 @@ void GlobalClassHandler::SetupGlobalClass(const ArenaVector & + ir::ClassDefinition *const globalClass = globalDecl->Definition(); +  + // NOTE(vpukhov): a clash inside program list is possible +- ES2PANDA_ASSERT(globalProgram->IsPackage() || programs.size() == 1); ++ // ES2PANDA_ASSERT(globalProgram->IsPackage() || programs.size() == 1); +  + ArenaVector statements(allocator_->Adapter()); + ArenaVector namespaces(allocator_->Adapter()); +@@ -233,12 +231,13 @@ void GlobalClassHandler::SetupGlobalClass(const ArenaVector & + return false; + }); + body.erase(end, body.end()); ++ program->Ast()->SetStatements(std::move(body)); + // NOTE: Initializer block for Package is to be done(xingshunxiang). + statements.emplace_back(GlobalStmts {program, std::move(stmts[0])}); + program->SetGlobalClass(globalClass); + } +  +- globalProgram->Ast()->Statements().emplace_back(globalDecl); ++ globalProgram->Ast()->AddStatement(globalDecl); + globalDecl->SetParent(globalProgram->Ast()); + globalClass->SetGlobalInitialized(); +  +@@ -298,7 +297,7 @@ void GlobalClassHandler::AddInitCallFromStaticBlock(ir::ClassDefinition *globalC + auto *blockBody = staticBlock->Function()->Body()->AsBlockStatement(); + auto exprStmt = NodeAllocator::Alloc(allocator_, callExpr); + exprStmt->SetParent(blockBody); +- blockBody->Statements().emplace_back(exprStmt); ++ blockBody->AddStatement(exprStmt); + } +  + ir::Identifier *GlobalClassHandler::RefIdent(const util::StringView &name) +@@ -485,7 +484,7 @@ ir::ClassDeclaration *GlobalClassHandler::CreateGlobalClass(const parser::Progra +  + auto *annotationModule = CreateModuleAnnotation(classDef->Range()); + annotationModule->SetParent(classDef); +- classDef->Annotations().push_back(annotationModule); ++ classDef->AddAnnotations(annotationModule); +  + return classDecl; + } +diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h +index ad42782ee..c266344ab 100644 +--- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h ++++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h +@@ -56,8 +56,8 @@ private: + void SetupGlobalMethods(parser::Program *program, ArenaVector &&initStatements, + ArenaVector &&initializerBlock, ir::ClassDefinition *globalClass, + bool isDeclare); +- ArenaVector TransformNamespaces(ArenaVector &namespaces, +- parser::Program *program); ++ ArenaVector TransformNamespaces(ArenaVector &namespaces, ++ parser::Program *program); +  + ir::ClassDeclaration *CreateGlobalClass(const parser::Program *globalProgram); + ir::ClassStaticBlock *CreateStaticBlock(ir::ClassDefinition *classDef); +diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp +index 9df08d538..852481bcc 100644 +--- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp ++++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalDeclTransformer.cpp +@@ -58,7 +58,7 @@ void GlobalDeclTransformer::VisitFunctionDeclaration(ir::FunctionDeclaration *fu + allocator_, methodKind, funcDecl->Function()->Id()->Clone(allocator_, nullptr), funcExpr, + funcDecl->Function()->Modifiers(), allocator_, false); + method->SetRange(funcDecl->Range()); +- method->Function()->SetAnnotations(std::move(funcDecl->Annotations())); ++ method->Function()->SetAnnotations(funcDecl->StealAnnotations()); +  + if (funcDecl->Function()->IsExported() && funcDecl->Function()->HasExportAlias()) { + method->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS); +diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp +index 76ff3a59f..0d11b6e3c 100644 +--- a/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp ++++ b/ets2panda/compiler/lowering/ets/topLevelStmts/importExportDecls.cpp +@@ -379,6 +379,7 @@ void ImportExportDecls::PreMergeNamespaces(parser::Program *program) + } +  + isChanged |= (originalSize != body.size()); ++ ast->AsETSModule()->SetStatements(std::move(body)); + }; +  + do { +diff --git a/ets2panda/compiler/lowering/ets/unionLowering.cpp b/ets2panda/compiler/lowering/ets/unionLowering.cpp +index 9fcbc3541..1d604f43a 100644 +--- a/ets2panda/compiler/lowering/ets/unionLowering.cpp ++++ b/ets2panda/compiler/lowering/ets/unionLowering.cpp +@@ -65,7 +65,7 @@ static ir::ClassDefinition *GetUnionAccessClass(checker::ETSChecker *checker, va +  + auto globalBlock = varbinder->Program()->Ast(); + classDecl->SetParent(globalBlock); +- globalBlock->Statements().push_back(classDecl); ++ globalBlock->AddStatement(classDecl); + classDecl->Check(checker); + return classDef; + } +diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp +index 6d153cc3e..74ea6fd62 100644 +--- a/ets2panda/compiler/lowering/phase.cpp ++++ b/ets2panda/compiler/lowering/phase.cpp +@@ -213,6 +213,16 @@ void SetPhaseManager(PhaseManager *phaseManager) + g_phaseManager = phaseManager; + } +  ++void PhaseManager::Restart() ++{ ++ prev_ = INVALID_PHASE_ID; ++ curr_ = PARSER_PHASE_ID; ++ next_ = PARSER_PHASE_ID + 1; ++ ES2PANDA_ASSERT(next_ == 0); ++ ++ SetPhaseManager(this); ++} ++ + bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) + { + SetPhaseManager(ctx->phaseManager); +diff --git a/ets2panda/compiler/lowering/phase.h b/ets2panda/compiler/lowering/phase.h +index e1ff9c388..d5c68a385 100644 +--- a/ets2panda/compiler/lowering/phase.h ++++ b/ets2panda/compiler/lowering/phase.h +@@ -124,13 +124,7 @@ public: + return allocator_ != nullptr && ext_ != ScriptExtension::INVALID; + } +  +- void Restart() +- { +- prev_ = INVALID_PHASE_ID; +- curr_ = PARSER_PHASE_ID; +- next_ = PARSER_PHASE_ID + 1; +- ES2PANDA_ASSERT(next_ == 0); +- } ++ void Restart(); +  + Phase *NextPhase() + { +diff --git a/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp b/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp +index e78fd348d..e1101e2b0 100644 +--- a/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp ++++ b/ets2panda/evaluate/debugInfoDeserialization/classBuilder.cpp +@@ -68,7 +68,7 @@ ir::ClassDeclaration *ClassBuilder::Build(parser::Program *program) && + classDecl->SetParent(programAst); + // Here we assume that global statements of the passed `program` are not currently checked, so that + // insertion is safe. +- programAst->Statements().push_back(classDecl); ++ programAst->AddStatement(classDecl); +  + return classDecl; + } +diff --git a/ets2panda/ir/annotationAllowed.h b/ets2panda/ir/annotationAllowed.h +index 30a2dcf4a..931701848 100644 +--- a/ets2panda/ir/annotationAllowed.h ++++ b/ets2panda/ir/annotationAllowed.h +@@ -31,24 +31,44 @@ public: + NO_COPY_OPERATOR(AnnotationAllowed); + NO_MOVE_SEMANTIC(AnnotationAllowed); +  +- [[nodiscard]] ArenaVector &Annotations() noexcept ++ void TransformAnnotations(const NodeTransformer &cb, std::string_view const transformationName) + { +- return annotations_; ++ const auto &constAnnotations = Annotations(); ++ for (size_t index = 0; index < constAnnotations.size(); ++index) { ++ auto annotation = constAnnotations[index]; ++ if (auto transformedNode = cb(annotation); annotation != transformedNode) { ++ annotation->SetTransformedNode(transformationName, transformedNode); ++ auto &annotations = AstNode::GetOrCreateHistoryNodeAs>()->annotations_; ++ annotations[index] = transformedNode->AsAnnotationUsage(); ++ } ++ } ++ } ++ ++ ArenaVector &&StealAnnotations() ++ { ++ return std::move(AstNode::GetOrCreateHistoryNodeAs>()->annotations_); + } +  + [[nodiscard]] const ArenaVector &Annotations() const noexcept + { +- return annotations_; ++ return AstNode::GetHistoryNodeAs>()->annotations_; + } +  +- void SetAnnotations(ArenaVector &&annotations) ++ void SetAnnotations(ArenaVector &&annotationList) + { +- annotations_ = std::move(annotations); +- for (ir::AnnotationUsage *anno : annotations_) { +- anno->SetParent(this); ++ auto &annotations = AstNode::GetOrCreateHistoryNodeAs>()->annotations_; ++ annotations = ArenaVector {std::move(annotationList)}; ++ ++ for (auto annotation : Annotations()) { ++ annotation->SetParent(this); + } + } +  ++ void AddAnnotations(AnnotationUsage *annotations) ++ { ++ AstNode::GetOrCreateHistoryNodeAs>()->annotations_.emplace_back(annotations); ++ } ++ + protected: + explicit AnnotationAllowed(Expression const &other, ArenaAllocator *allocator) + : T(other), annotations_(allocator->Adapter()) +@@ -82,11 +102,6 @@ protected: + { + } +  +- void AddAnnotations(AnnotationUsage *const annotations) +- { +- annotations_.emplace_back(annotations); +- } +- + AnnotationAllowed(AnnotationAllowed const &other) + : T(static_cast(other)), annotations_(other.annotations_.get_allocator()) + { +diff --git a/ets2panda/ir/as/namedType.cpp b/ets2panda/ir/as/namedType.cpp +index 7bf5f66ec..48880e158 100644 +--- a/ets2panda/ir/as/namedType.cpp ++++ b/ets2panda/ir/as/namedType.cpp +@@ -45,12 +45,7 @@ void NamedType::TransformChildren(const NodeTransformer &cb, std::string_view co + } + } +  +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void NamedType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/astNode.cpp b/ets2panda/ir/astNode.cpp +index 31a4a72a4..e56f548b8 100644 +--- a/ets2panda/ir/astNode.cpp ++++ b/ets2panda/ir/astNode.cpp +@@ -24,20 +24,21 @@ namespace ark::es2panda::ir { +  + AstNode::AstNode(AstNode const &other) + { +- range_ = other.range_; +- type_ = other.type_; +- if (other.variable_ != nullptr) { +- variable_ = other.variable_; ++ auto otherHistoryNode = other.GetHistoryNode(); ++ range_ = otherHistoryNode->range_; ++ type_ = otherHistoryNode->type_; ++ if (otherHistoryNode->variable_ != nullptr) { ++ variable_ = otherHistoryNode->variable_; + } +- flags_ = other.flags_; +- astNodeFlags_ = other.astNodeFlags_; ++ flags_ = otherHistoryNode->flags_; ++ astNodeFlags_ = otherHistoryNode->astNodeFlags_; + // boxing_unboxing_flags_ {}; leave default value! + } +  + [[nodiscard]] bool AstNode::IsExported() const noexcept + { + if (UNLIKELY(IsClassDefinition())) { +- return parent_->IsExported(); ++ return GetHistoryNode()->parent_->IsExported(); + } +  + return (Modifiers() & ModifierFlags::EXPORT) != 0; +@@ -46,7 +47,7 @@ AstNode::AstNode(AstNode const &other) + [[nodiscard]] bool AstNode::IsDefaultExported() const noexcept + { + if (UNLIKELY(IsClassDefinition())) { +- return parent_->IsDefaultExported(); ++ return GetHistoryNode()->parent_->IsDefaultExported(); + } +  + return (Modifiers() & ModifierFlags::DEFAULT_EXPORT) != 0; +@@ -55,7 +56,7 @@ AstNode::AstNode(AstNode const &other) + [[nodiscard]] bool AstNode::IsExportedType() const noexcept + { + if (UNLIKELY(IsClassDefinition())) { +- return this->parent_->IsExportedType(); ++ return GetHistoryNode()->parent_->IsExportedType(); + } +  + return (Modifiers() & ModifierFlags::EXPORT_TYPE) != 0; +@@ -64,10 +65,10 @@ AstNode::AstNode(AstNode const &other) + [[nodiscard]] bool AstNode::HasExportAlias() const noexcept + { + if (UNLIKELY(IsClassDefinition())) { +- return parent_->HasExportAlias(); ++ return GetHistoryNode()->parent_->HasExportAlias(); + } +  +- return (astNodeFlags_ & AstNodeFlags::HAS_EXPORT_ALIAS) != 0; ++ return (GetHistoryNode()->astNodeFlags_ & AstNodeFlags::HAS_EXPORT_ALIAS) != 0; + } +  + bool AstNode::IsScopeBearer() const noexcept +@@ -235,19 +236,30 @@ std::string AstNode::DumpEtsSrc() const +  + void AstNode::SetOriginalNode(AstNode *originalNode) noexcept + { +- originalNode_ = originalNode; ++ if (OriginalNode() != originalNode) { ++ GetOrCreateHistoryNode()->originalNode_ = originalNode; ++ } + } +  + AstNode *AstNode::OriginalNode() const noexcept + { +- return originalNode_; ++ return GetHistoryNode()->originalNode_; ++} ++ ++const std::optional> &AstNode::TransformedNode() const noexcept ++{ ++ return GetHistoryNode()->transformedNode_; + } +  + void AstNode::SetTransformedNode(std::string_view const transformationName, AstNode *transformedNode) + { +- ES2PANDA_ASSERT(!transformedNode_.has_value()); ++ ES2PANDA_ASSERT(!TransformedNode().has_value()); + transformedNode->SetOriginalNode(this); +- transformedNode_ = std::make_optional(std::make_pair(transformationName, transformedNode)); ++ ++ if (transformedNode != nullptr) { ++ GetOrCreateHistoryNode()->transformedNode_ = ++ std::make_optional(std::make_pair(transformationName, transformedNode)); ++ } + } +  + void AstNode::CleanUp() +@@ -319,21 +331,21 @@ AstNode *AstNode::Construct([[maybe_unused]] ArenaAllocator *allocator) + ES2PANDA_UNREACHABLE(); + } +  +-const AstNode *AstNode::GetHistoryNode() const ++AstNode *AstNode::GetHistoryNode() const + { +- const AstNode *node = nullptr; ++ AstNode *node = nullptr; +  + if (HistoryEnabled()) { + node = history_->Get(compiler::GetPhaseManager()->CurrentPhaseId()); + } else { +- node = this; ++ node = const_cast(this); + } +  + ES2PANDA_ASSERT(node != nullptr); + return node; + } +  +-AstNode *AstNode::GetOrCreateHistoryNode() ++AstNode *AstNode::GetOrCreateHistoryNode() const + { + AstNode *node = nullptr; +  +@@ -346,7 +358,11 @@ AstNode *AstNode::GetOrCreateHistoryNode() + history_->Set(node, compiler::GetPhaseManager()->CurrentPhaseId()); + } + } else { +- node = this; ++ node = const_cast(this); ++ } ++ ++ if (node == (void *)0x7fffde210330) { ++ std::cout << "node == 0x7fffde210330" << std::endl; + } +  + return node; +@@ -372,8 +388,8 @@ void AstNode::EnableHistory() + return; + } +  +- history_ = compiler::GetPhaseManager()->Allocator()->New( +- this, compiler::GetPhaseManager()->CurrentPhaseId(), compiler::GetPhaseManager()->Allocator()); ++ // history_ = compiler::GetPhaseManager()->Allocator()->New( ++ // this, compiler::GetPhaseManager()->CurrentPhaseId(), compiler::GetPhaseManager()->Allocator()); + } +  + bool AstNode::HistoryEnabled() const +diff --git a/ets2panda/ir/astNode.h b/ets2panda/ir/astNode.h +index d9f6eebd1..415c461f9 100644 +--- a/ets2panda/ir/astNode.h ++++ b/ets2panda/ir/astNode.h +@@ -128,31 +128,31 @@ public: +  + bool IsProgram() const + { +- return parent_ == nullptr; ++ return GetHistoryNode()->parent_ == nullptr; + } +  + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +-#define DECLARE_IS_CHECKS(nodeType, className) \ +- bool Is##className() const \ +- { \ +- /* CC-OFFNXT(G.PRE.02) name part*/ \ +- /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ +- return type_ == AstNodeType::nodeType; /* CC-OFF(G.PRE.02) name part*/ \ ++#define DECLARE_IS_CHECKS(nodeType, className) \ ++ bool Is##className() const \ ++ { \ ++ /* CC-OFFNXT(G.PRE.02) name part*/ \ ++ /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ ++ return GetHistoryNode()->type_ == AstNodeType::nodeType; /* CC-OFF(G.PRE.02) name part*/ \ + } + AST_NODE_MAPPING(DECLARE_IS_CHECKS) + #undef DECLARE_IS_CHECKS +  + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +-#define DECLARE_IS_CHECKS(nodeType1, nodeType2, baseClass, reinterpretClass) \ +- bool Is##baseClass() const \ +- { \ +- /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ +- return type_ == AstNodeType::nodeType1; /* CC-OFF(G.PRE.02) name part*/ \ +- } \ +- bool Is##reinterpretClass() const \ +- { \ +- /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ +- return type_ == AstNodeType::nodeType2; /* CC-OFF(G.PRE.02) name part*/ \ ++#define DECLARE_IS_CHECKS(nodeType1, nodeType2, baseClass, reinterpretClass) \ ++ bool Is##baseClass() const \ ++ { \ ++ /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ ++ return GetHistoryNode()->type_ == AstNodeType::nodeType1; /* CC-OFF(G.PRE.02) name part*/ \ ++ } \ ++ bool Is##reinterpretClass() const \ ++ { \ ++ /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed */ \ ++ return GetHistoryNode()->type_ == AstNodeType::nodeType2; /* CC-OFF(G.PRE.02) name part*/ \ + } + AST_NODE_REINTERPRET_MAPPING(DECLARE_IS_CHECKS) + #undef DECLARE_IS_CHECKS +@@ -266,68 +266,72 @@ public: +  + void SetRange(const lexer::SourceRange &loc) noexcept + { +- range_ = loc; ++ if (GetHistoryNode()->range_ != loc) { ++ GetOrCreateHistoryNode()->range_ = loc; ++ } + } +  + void SetStart(const lexer::SourcePosition &start) noexcept + { +- range_.start = start; ++ if (GetHistoryNode()->range_.start != start) { ++ GetOrCreateHistoryNode()->range_.start = start; ++ } + } +  + void SetEnd(const lexer::SourcePosition &end) noexcept + { +- range_.end = end; ++ if (GetHistoryNode()->range_.end != end) { ++ GetOrCreateHistoryNode()->range_.end = end; ++ } + } +  + [[nodiscard]] const lexer::SourcePosition &Start() const noexcept + { +- return range_.start; ++ return GetHistoryNode()->range_.start; + } +  + [[nodiscard]] const lexer::SourcePosition &End() const noexcept + { +- return range_.end; ++ return GetHistoryNode()->range_.end; + } +  + [[nodiscard]] const lexer::SourceRange &Range() const noexcept + { +- return range_; ++ return GetHistoryNode()->range_; + } +  + [[nodiscard]] AstNodeType Type() const noexcept + { +- return type_; ++ return GetHistoryNode()->type_; + } +  + [[nodiscard]] AstNode *Parent() noexcept + { +- return parent_; ++ return GetHistoryNode()->parent_; + } +  + [[nodiscard]] const AstNode *Parent() const noexcept + { +- return parent_; ++ return GetHistoryNode()->parent_; + } +  + void SetParent(AstNode *const parent) noexcept + { +- parent_ = parent; ++ if (GetHistoryNode()->parent_ != parent) { ++ GetOrCreateHistoryNode()->parent_ = parent; ++ } + } +  + [[nodiscard]] varbinder::Variable *Variable() const noexcept + { +- return variable_; ++ return GetHistoryNode()->variable_; + } +  + void SetVariable(varbinder::Variable *variable) noexcept + { +- variable_ = variable; +- } +- +- // When no decorators are allowed, we cannot return a reference to an empty vector. +- virtual const ArenaVector *DecoratorsPtr() const +- { +- return nullptr; ++ if (GetHistoryNode()->variable_ != variable) { ++ GetOrCreateHistoryNode()->variable_ = variable; ++ } + } +  + virtual void AddDecorators([[maybe_unused]] ArenaVector &&decorators) +@@ -459,28 +463,34 @@ public: + #define DECLARE_FLAG_OPERATIONS(flag_type, member_name) \ + void Set##flag_type(flag_type flags) const noexcept \ + { \ +- (member_name) = flags; \ ++ if (GetHistoryNode()->member_name != flags) { \ ++ GetOrCreateHistoryNode()->member_name = flags; \ ++ } \ + } \ + \ + void Add##flag_type(flag_type flag) const noexcept \ + { \ +- (member_name) |= flag; \ ++ if (!All(GetHistoryNode()->member_name, flag)) { \ ++ GetOrCreateHistoryNode()->member_name |= flag; \ ++ } \ + } \ + \ + [[nodiscard]] flag_type Get##flag_type() const noexcept \ + { \ + /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ +- return (member_name); \ ++ return GetHistoryNode()->member_name; \ + } \ + \ + bool Has##flag_type(flag_type flag) const noexcept \ + { \ + /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ +- return ((member_name)&flag) != 0U; \ ++ return (GetHistoryNode()->member_name & flag) != 0U; \ + } \ + void Remove##flag_type(flag_type flag) const noexcept \ + { \ +- (member_name) &= ~flag; \ ++ if (Any(GetHistoryNode()->member_name, flag)) { \ ++ GetOrCreateHistoryNode()->member_name &= ~flag; \ ++ } \ + } +  + DECLARE_FLAG_OPERATIONS(BoxingUnboxingFlags, boxingUnboxingFlags_); +@@ -554,13 +564,28 @@ protected: +  + void SetType(AstNodeType const type) noexcept + { +- type_ = type; ++ if (Type() != type) { ++ GetOrCreateHistoryNode()->type_ = type; ++ } + } +  + void EnableHistory(); + bool HistoryEnabled() const; +- const AstNode *GetHistoryNode() const; +- AstNode *GetOrCreateHistoryNode(); ++ ++ AstNode *GetHistoryNode() const; ++ AstNode *GetOrCreateHistoryNode() const; ++ ++ template  ++ T *GetHistoryNodeAs() const ++ { ++ return reinterpret_cast(GetHistoryNode()); ++ } ++ ++ template  ++ T *GetOrCreateHistoryNodeAs() const ++ { ++ return reinterpret_cast(GetOrCreateHistoryNode()); ++ } +  + // NOLINTBEGIN(misc-non-private-member-variables-in-classes) + AstNode *parent_ {}; +@@ -575,6 +600,8 @@ protected: + private: + AstNode &operator=(const AstNode &) = default; +  ++ const std::optional> &TransformedNode() const noexcept; ++ + varbinder::Variable *variable_ {}; + AstNode *originalNode_ = nullptr; + // {lowering_phase_name, new_generated_node} +@@ -592,12 +619,14 @@ public: +  + [[nodiscard]] TypeNode *TypeAnnotation() const noexcept + { +- return typeAnnotation_; ++ return AstNode::GetHistoryNodeAs>()->typeAnnotation_; + } +  + void SetTsTypeAnnotation(TypeNode *const typeAnnotation) noexcept + { +- typeAnnotation_ = typeAnnotation; ++ if (TypeAnnotation() != typeAnnotation) { ++ AstNode::GetOrCreateHistoryNodeAs>()->typeAnnotation_ = typeAnnotation; ++ } + } +  + void CopyTo(AstNode *other) const override +diff --git a/ets2panda/ir/base/classDefinition.cpp b/ets2panda/ir/base/classDefinition.cpp +index 003591143..29cd5cd06 100644 +--- a/ets2panda/ir/base/classDefinition.cpp ++++ b/ets2panda/ir/base/classDefinition.cpp +@@ -99,12 +99,7 @@ void ClassDefinition::TransformChildren(const NodeTransformer &cb, std::string_v + } + } +  +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); +  + if (ctor_ != nullptr) { + if (auto *transformedNode = cb(ctor_); ctor_ != transformedNode) { +diff --git a/ets2panda/ir/base/classElement.cpp b/ets2panda/ir/base/classElement.cpp +index a861f1c13..12b7d218a 100644 +--- a/ets2panda/ir/base/classElement.cpp ++++ b/ets2panda/ir/base/classElement.cpp +@@ -22,20 +22,26 @@ namespace ark::es2panda::ir { +  + void ClassElement::SetValue(Expression *value) noexcept + { ++ if (Value() == value) { ++ return; ++ } ++ + if (value != nullptr) { + value->SetParent(this); + } +- value_ = value; ++ AstNode::GetOrCreateHistoryNodeAs()->value_ = value; + } +  + Identifier *ClassElement::Id() noexcept + { +- return key_ != nullptr && key_->IsIdentifier() ? key_->AsIdentifier() : nullptr; ++ auto key = Key(); ++ return key != nullptr && key->IsIdentifier() ? key->AsIdentifier() : nullptr; + } +  + const Identifier *ClassElement::Id() const noexcept + { +- return key_ != nullptr && key_->IsIdentifier() ? key_->AsIdentifier() : nullptr; ++ auto key = Key(); ++ return key != nullptr && key->IsIdentifier() ? key->AsIdentifier() : nullptr; + } +  + bool ClassElement::IsPrivateElement() const noexcept +@@ -44,7 +50,8 @@ bool ClassElement::IsPrivateElement() const noexcept + return false; + } +  +- return key_->IsIdentifier() && key_->AsIdentifier()->IsPrivateIdent(); ++ auto key = Key(); ++ return key->IsIdentifier() && key->AsIdentifier()->IsPrivateIdent(); + } +  + void ClassElement::CopyTo(AstNode *other) const +diff --git a/ets2panda/ir/base/classElement.h b/ets2panda/ir/base/classElement.h +index 8ab79507c..7a4ac12c0 100644 +--- a/ets2panda/ir/base/classElement.h ++++ b/ets2panda/ir/base/classElement.h +@@ -46,62 +46,59 @@ public: +  + [[nodiscard]] Expression *Key() noexcept + { +- return key_; ++ return AstNode::GetHistoryNodeAs()->key_; + } +  + [[nodiscard]] const Expression *Key() const noexcept + { +- return key_; ++ return AstNode::GetHistoryNodeAs()->key_; + } +  + [[nodiscard]] Expression *Value() noexcept + { +- return value_; ++ return AstNode::GetHistoryNodeAs()->value_; + } +  + void SetValue(Expression *value) noexcept; +  + [[nodiscard]] const Expression *Value() const noexcept + { +- return value_; ++ return AstNode::GetHistoryNodeAs()->value_; + } +  + [[nodiscard]] const TSEnumMember *OriginEnumMember() const noexcept + { +- return enumMember_; ++ return AstNode::GetHistoryNodeAs()->enumMember_; + } +  + void SetOrigEnumMember(ir::TSEnumMember *enumMember) + { +- enumMember_ = enumMember; ++ if (OriginEnumMember() != enumMember) { ++ AstNode::GetOrCreateHistoryNodeAs()->enumMember_ = enumMember; ++ } + } +  + [[nodiscard]] bool IsPrivateElement() const noexcept; +  + [[nodiscard]] const ArenaVector &Decorators() const noexcept + { +- return decorators_; +- } +- +- const ArenaVector *DecoratorsPtr() const override +- { +- return &Decorators(); ++ return AstNode::GetHistoryNodeAs()->decorators_; + } +  + [[nodiscard]] bool IsComputed() const noexcept + { +- return isComputed_; ++ return AstNode::GetHistoryNodeAs()->isComputed_; + } +  + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override + { +- decorators_ = std::move(decorators); ++ AstNode::GetHistoryNodeAs()->decorators_ = std::move(decorators); + } +  + void AddDecorator(ir::Decorator *const decorator) + { + if (decorator != nullptr) { +- decorators_.emplace_back(decorator); ++ AstNode::GetOrCreateHistoryNodeAs()->decorators_.emplace_back(decorator); + } + } +  +diff --git a/ets2panda/ir/base/classProperty.cpp b/ets2panda/ir/base/classProperty.cpp +index 85ab934be..81f948dc6 100644 +--- a/ets2panda/ir/base/classProperty.cpp ++++ b/ets2panda/ir/base/classProperty.cpp +@@ -49,12 +49,7 @@ void ClassProperty::TransformChildren(const NodeTransformer &cb, std::string_vie + } + } +  +- for (auto *&it : Annotations()) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ClassProperty::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/base/scriptFunction.cpp b/ets2panda/ir/base/scriptFunction.cpp +index 49abf8a90..21a51429b 100644 +--- a/ets2panda/ir/base/scriptFunction.cpp ++++ b/ets2panda/ir/base/scriptFunction.cpp +@@ -112,12 +112,7 @@ void ScriptFunction::TransformChildren(const NodeTransformer &cb, std::string_vi + } + } +  +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ScriptFunction::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/base/spreadElement.h b/ets2panda/ir/base/spreadElement.h +index 803e8e32a..f9eefb502 100644 +--- a/ets2panda/ir/base/spreadElement.h ++++ b/ets2panda/ir/base/spreadElement.h +@@ -59,11 +59,6 @@ public: + return decorators_; + } +  +- const ArenaVector *DecoratorsPtr() const override +- { +- return &Decorators(); +- } +- + void AddDecorators(ArenaVector &&decorators) override + { + decorators_ = std::move(decorators); +diff --git a/ets2panda/ir/ets/etsFunctionType.cpp b/ets2panda/ir/ets/etsFunctionType.cpp +index da4e93b20..6204a9090 100644 +--- a/ets2panda/ir/ets/etsFunctionType.cpp ++++ b/ets2panda/ir/ets/etsFunctionType.cpp +@@ -24,12 +24,7 @@ namespace ark::es2panda::ir { + void ETSFunctionType::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) + { + signature_.TransformChildren(cb, transformationName); +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ETSFunctionType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ets/etsNeverType.cpp b/ets2panda/ir/ets/etsNeverType.cpp +index 79284dd1f..3f40e3475 100644 +--- a/ets2panda/ir/ets/etsNeverType.cpp ++++ b/ets2panda/ir/ets/etsNeverType.cpp +@@ -21,12 +21,7 @@ namespace ark::es2panda::ir { + void ETSNeverType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ETSNeverType::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ets/etsNullishTypes.cpp b/ets2panda/ir/ets/etsNullishTypes.cpp +index e3e9e7983..0957d162a 100644 +--- a/ets2panda/ir/ets/etsNullishTypes.cpp ++++ b/ets2panda/ir/ets/etsNullishTypes.cpp +@@ -21,12 +21,7 @@ namespace ark::es2panda::ir { + void ETSUndefinedType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ETSUndefinedType::Iterate([[maybe_unused]] const NodeTraverser &cb) const +@@ -92,12 +87,7 @@ ETSUndefinedType *ETSUndefinedType::Clone(ArenaAllocator *allocator, AstNode *pa + void ETSNullType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ETSNullType::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ets/etsParameterExpression.cpp b/ets2panda/ir/ets/etsParameterExpression.cpp +index 2304b38b1..4015934e5 100644 +--- a/ets2panda/ir/ets/etsParameterExpression.cpp ++++ b/ets2panda/ir/ets/etsParameterExpression.cpp +@@ -144,12 +144,7 @@ void ETSParameterExpression::TransformChildren(const NodeTransformer &cb, std::s + } + } +  +- for (auto *&it : Annotations()) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ETSParameterExpression::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ets/etsPrimitiveType.cpp b/ets2panda/ir/ets/etsPrimitiveType.cpp +index c18f74350..20708e304 100644 +--- a/ets2panda/ir/ets/etsPrimitiveType.cpp ++++ b/ets2panda/ir/ets/etsPrimitiveType.cpp +@@ -24,12 +24,7 @@ namespace ark::es2panda::ir { + void ETSPrimitiveType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ETSPrimitiveType::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ets/etsStringLiteralType.cpp b/ets2panda/ir/ets/etsStringLiteralType.cpp +index d6227f267..178160de4 100644 +--- a/ets2panda/ir/ets/etsStringLiteralType.cpp ++++ b/ets2panda/ir/ets/etsStringLiteralType.cpp +@@ -21,12 +21,7 @@ namespace ark::es2panda::ir { + void ETSStringLiteralType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ETSStringLiteralType::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ets/etsTuple.cpp b/ets2panda/ir/ets/etsTuple.cpp +index ff18faae7..abc977a81 100644 +--- a/ets2panda/ir/ets/etsTuple.cpp ++++ b/ets2panda/ir/ets/etsTuple.cpp +@@ -29,12 +29,7 @@ void ETSTuple::TransformChildren(const NodeTransformer &cb, std::string_view con + } + } +  +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ETSTuple::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ets/etsTypeReference.cpp b/ets2panda/ir/ets/etsTypeReference.cpp +index 7be302475..a1c8b14ab 100644 +--- a/ets2panda/ir/ets/etsTypeReference.cpp ++++ b/ets2panda/ir/ets/etsTypeReference.cpp +@@ -27,12 +27,8 @@ void ETSTypeReference::TransformChildren(const NodeTransformer &cb, std::string_ + part_->SetTransformedNode(transformationName, transformedNode); + part_ = transformedNode->AsETSTypeReferencePart(); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void ETSTypeReference::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ets/etsUnionType.cpp b/ets2panda/ir/ets/etsUnionType.cpp +index 39860832e..a64059e95 100644 +--- a/ets2panda/ir/ets/etsUnionType.cpp ++++ b/ets2panda/ir/ets/etsUnionType.cpp +@@ -26,12 +26,8 @@ void ETSUnionType::TransformChildren(const NodeTransformer &cb, std::string_view + it = static_cast(transformedNode); + } + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void ETSUnionType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ets/etsWildcardType.cpp b/ets2panda/ir/ets/etsWildcardType.cpp +index 24000a8aa..ab5ffc9e5 100644 +--- a/ets2panda/ir/ets/etsWildcardType.cpp ++++ b/ets2panda/ir/ets/etsWildcardType.cpp +@@ -32,12 +32,8 @@ void ETSWildcardType::TransformChildren(const NodeTransformer &cb, std::string_v + typeReference_ = transformedNode->AsETSTypeReference(); + } + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void ETSWildcardType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/expression.h b/ets2panda/ir/expression.h +index cc4beaba3..79efec30c 100644 +--- a/ets2panda/ir/expression.h ++++ b/ets2panda/ir/expression.h +@@ -33,12 +33,14 @@ public: +  + [[nodiscard]] bool IsGrouped() const noexcept + { +- return grouped_; ++ return AstNode::GetHistoryNodeAs()->grouped_; + } +  + void SetGrouped() noexcept + { +- grouped_ = true; ++ if (!IsGrouped()) { ++ AstNode::GetOrCreateHistoryNodeAs()->grouped_ = true; ++ } + } +  + [[nodiscard]] const Literal *AsLiteral() const +@@ -109,7 +111,7 @@ protected: +  + Expression(Expression const &other) : TypedAstNode(static_cast(other)) + { +- grouped_ = other.grouped_; ++ grouped_ = other.IsGrouped(); + } +  + private: +diff --git a/ets2panda/ir/expressions/arrayExpression.h b/ets2panda/ir/expressions/arrayExpression.h +index ddf8ceb49..578678b65 100644 +--- a/ets2panda/ir/expressions/arrayExpression.h ++++ b/ets2panda/ir/expressions/arrayExpression.h +@@ -119,11 +119,6 @@ public: + return decorators_; + } +  +- const ArenaVector *DecoratorsPtr() const override +- { +- return &Decorators(); +- } +- + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override + { + decorators_ = std::move(decorators); +diff --git a/ets2panda/ir/expressions/arrowFunctionExpression.cpp b/ets2panda/ir/expressions/arrowFunctionExpression.cpp +index 9ba12344a..8265cfbba 100644 +--- a/ets2panda/ir/expressions/arrowFunctionExpression.cpp ++++ b/ets2panda/ir/expressions/arrowFunctionExpression.cpp +@@ -28,12 +28,7 @@ void ArrowFunctionExpression::TransformChildren(const NodeTransformer &cb, std:: + func_ = transformedNode->AsScriptFunction(); + } +  +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void ArrowFunctionExpression::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/expressions/identifier.h b/ets2panda/ir/expressions/identifier.h +index da71df56c..83deda510 100644 +--- a/ets2panda/ir/expressions/identifier.h ++++ b/ets2panda/ir/expressions/identifier.h +@@ -83,11 +83,6 @@ public: + return decorators_; + } +  +- const ArenaVector *DecoratorsPtr() const override +- { +- return &Decorators(); +- } +- + bool IsErrorPlaceHolder() const noexcept + { + return (flags_ & IdentifierFlags::ERROR_PLACEHOLDER) != 0; +diff --git a/ets2panda/ir/expressions/objectExpression.h b/ets2panda/ir/expressions/objectExpression.h +index 7f7e05007..45e893cb5 100644 +--- a/ets2panda/ir/expressions/objectExpression.h ++++ b/ets2panda/ir/expressions/objectExpression.h +@@ -81,11 +81,6 @@ public: + return decorators_; + } +  +- const ArenaVector *DecoratorsPtr() const override +- { +- return &Decorators(); +- } +- + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override + { + decorators_ = std::move(decorators); +diff --git a/ets2panda/ir/opaqueTypeNode.cpp b/ets2panda/ir/opaqueTypeNode.cpp +index b76b69d86..4a74b3897 100644 +--- a/ets2panda/ir/opaqueTypeNode.cpp ++++ b/ets2panda/ir/opaqueTypeNode.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void OpaqueTypeNode::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void OpaqueTypeNode::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/statements/annotationDeclaration.cpp b/ets2panda/ir/statements/annotationDeclaration.cpp +index 447f3d60b..9b8ba83e2 100644 +--- a/ets2panda/ir/statements/annotationDeclaration.cpp ++++ b/ets2panda/ir/statements/annotationDeclaration.cpp +@@ -37,12 +37,7 @@ void AnnotationDeclaration::TransformChildren(const NodeTransformer &cb, std::st + } + } +  +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } + void AnnotationDeclaration::Iterate(const NodeTraverser &cb) const + { +diff --git a/ets2panda/ir/statements/blockStatement.cpp b/ets2panda/ir/statements/blockStatement.cpp +index 726332eaf..c30a15da6 100644 +--- a/ets2panda/ir/statements/blockStatement.cpp ++++ b/ets2panda/ir/statements/blockStatement.cpp +@@ -28,11 +28,13 @@ namespace ark::es2panda::ir { + void BlockStatement::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) + { + // This will survive pushing element to the back of statements_ in the process +- // NOLINTNEXTLINE(modernize-loop-convert) +- for (size_t ix = 0; ix < statements_.size(); ix++) { +- if (auto *transformedNode = cb(statements_[ix]); statements_[ix] != transformedNode) { +- statements_[ix]->SetTransformedNode(transformationName, transformedNode); +- statements_[ix] = transformedNode->AsStatement(); ++ auto const &constStatements = Statements(); ++ for (size_t index = 0; index < constStatements.size(); index++) { ++ auto statement = constStatements[index]; ++ if (auto *transformedNode = cb(statement); statement != transformedNode) { ++ statement->SetTransformedNode(transformationName, transformedNode); ++ auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; ++ statements[index] = transformedNode->AsStatement(); + } + } + } +@@ -41,7 +43,7 @@ AstNode *BlockStatement::Clone(ArenaAllocator *const allocator, AstNode *const p + { + ArenaVector statements(allocator->Adapter()); +  +- for (auto *statement : this->statements_) { ++ for (auto *statement : Statements()) { + statements.push_back(statement->Clone(allocator, parent)->AsStatement()); + } +  +@@ -55,8 +57,9 @@ void BlockStatement::Iterate(const NodeTraverser &cb) const + { + // This will survive pushing element to the back of statements_ in the process + // NOLINTNEXTLINE(modernize-loop-convert) +- for (size_t ix = 0; ix < statements_.size(); ix++) { +- cb(statements_[ix]); ++ auto const &statements = Statements(); ++ for (size_t ix = 0; ix < statements.size(); ix++) { ++ cb(statements[ix]); + } + } +  +@@ -67,22 +70,23 @@ void BlockStatement::Dump(ir::AstDumper *dumper) const +  + void BlockStatement::Dump(ir::SrcDumper *dumper) const + { ++ auto const &statements = Statements(); + // NOTE(nsizov): trailing blocks + if (Parent() != nullptr && (Parent()->IsBlockStatement() || Parent()->IsCallExpression())) { + dumper->Add("{"); +- if (!statements_.empty()) { ++ if (!statements.empty()) { + dumper->IncrIndent(); + dumper->Endl(); + } + } +- for (auto statement : statements_) { ++ for (auto statement : statements) { + statement->Dump(dumper); +- if (statement != statements_.back()) { ++ if (statement != statements.back()) { + dumper->Endl(); + } + } + if (Parent() != nullptr && (Parent()->IsBlockStatement() || Parent()->IsCallExpression())) { +- if (!statements_.empty()) { ++ if (!statements.empty()) { + dumper->DecrIndent(); + dumper->Endl(); + } +diff --git a/ets2panda/ir/statements/blockStatement.h b/ets2panda/ir/statements/blockStatement.h +index 5100331df..8aa4728c4 100644 +--- a/ets2panda/ir/statements/blockStatement.h ++++ b/ets2panda/ir/statements/blockStatement.h +@@ -42,41 +42,65 @@ public: +  + [[nodiscard]] varbinder::Scope *Scope() const noexcept override + { +- return scope_; ++ return AstNode::GetHistoryNodeAs()->scope_; + } +  + void SetScope(varbinder::Scope *scope) noexcept + { +- scope_ = scope; ++ if (Scope() != scope) { ++ AstNode::GetOrCreateHistoryNodeAs()->scope_ = scope; ++ } + } +  + void ClearScope() noexcept override + { +- scope_ = nullptr; ++ SetScope(nullptr); + } +  +- const ArenaVector &Statements() const ++ ArenaVector &Statements() + { +- return statements_; ++ return AstNode::GetOrCreateHistoryNodeAs()->statements_; + } +  +- ArenaVector &Statements() ++ const ArenaVector &Statements() const + { +- return statements_; ++ return AstNode::GetHistoryNodeAs()->statements_; + } +  + void SetStatements(ArenaVector &&statementList) + { +- statements_ = std::move(statementList); ++ auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; ++ statements = std::move(statementList); +  +- for (auto *statement : statements_) { ++ for (auto *statement : Statements()) { + statement->SetParent(this); + } + } +  ++ void AddStatements(const ArenaVector &statementList) ++ { ++ auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; ++ ++ for (auto statement : statementList) { ++ statements.emplace_back(statement); ++ } ++ } ++ ++ void ClearStatements() ++ { ++ auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; ++ statements.clear(); ++ } ++ ++ void AddStatement(Statement *statement) ++ { ++ auto &statements = AstNode::GetOrCreateHistoryNodeAs()->statements_; ++ statements.emplace_back(statement); ++ } ++ + void AddTrailingBlock(AstNode *stmt, BlockStatement *trailingBlock) + { +- trailingBlocks_.emplace(stmt, trailingBlock); ++ AstNode::GetOrCreateHistoryNodeAs()->trailingBlocks_.emplace(stmt, trailingBlock); + } +  + void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; +diff --git a/ets2panda/ir/statements/classDeclaration.h b/ets2panda/ir/statements/classDeclaration.h +index 1299c4b7e..4c8482a1a 100644 +--- a/ets2panda/ir/statements/classDeclaration.h ++++ b/ets2panda/ir/statements/classDeclaration.h +@@ -41,11 +41,6 @@ public: + return decorators_; + } +  +- const ArenaVector *DecoratorsPtr() const override +- { +- return &Decorators(); +- } +- + void AddDecorators(ArenaVector &&decorators) override + { + decorators_ = std::move(decorators); +diff --git a/ets2panda/ir/statements/functionDeclaration.cpp b/ets2panda/ir/statements/functionDeclaration.cpp +index 82b9ff08f..de4b7c3d2 100644 +--- a/ets2panda/ir/statements/functionDeclaration.cpp ++++ b/ets2panda/ir/statements/functionDeclaration.cpp +@@ -32,12 +32,7 @@ void FunctionDeclaration::TransformChildren(const NodeTransformer &cb, std::stri + } + } +  +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); +  + if (auto *transformedNode = cb(func_); func_ != transformedNode) { + func_->SetTransformedNode(transformationName, transformedNode); +diff --git a/ets2panda/ir/statements/variableDeclaration.cpp b/ets2panda/ir/statements/variableDeclaration.cpp +index 205fa6897..8814a3190 100644 +--- a/ets2panda/ir/statements/variableDeclaration.cpp ++++ b/ets2panda/ir/statements/variableDeclaration.cpp +@@ -31,12 +31,7 @@ void VariableDeclaration::TransformChildren(const NodeTransformer &cb, std::stri + } + } +  +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); +  + for (auto *&it : VectorIterationGuard(declarators_)) { + if (auto *transformedNode = cb(it); it != transformedNode) { +diff --git a/ets2panda/ir/statements/variableDeclaration.h b/ets2panda/ir/statements/variableDeclaration.h +index 32604db27..5358d1cf2 100644 +--- a/ets2panda/ir/statements/variableDeclaration.h ++++ b/ets2panda/ir/statements/variableDeclaration.h +@@ -68,11 +68,6 @@ public: + return nullptr; + } +  +- const ArenaVector *DecoratorsPtr() const override +- { +- return &Decorators(); +- } +- + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override + { + decorators_ = std::move(decorators); +diff --git a/ets2panda/ir/ts/tsAnyKeyword.cpp b/ets2panda/ir/ts/tsAnyKeyword.cpp +index 99f5e085a..f8cde5748 100644 +--- a/ets2panda/ir/ts/tsAnyKeyword.cpp ++++ b/ets2panda/ir/ts/tsAnyKeyword.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void TSAnyKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSAnyKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsArrayType.cpp b/ets2panda/ir/ts/tsArrayType.cpp +index 8a1e1abd2..8ab2361fb 100644 +--- a/ets2panda/ir/ts/tsArrayType.cpp ++++ b/ets2panda/ir/ts/tsArrayType.cpp +@@ -27,12 +27,8 @@ void TSArrayType::TransformChildren(const NodeTransformer &cb, std::string_view + elementType_->SetTransformedNode(transformationName, transformedNode); + elementType_ = static_cast(transformedNode); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSArrayType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsBigintKeyword.cpp b/ets2panda/ir/ts/tsBigintKeyword.cpp +index 7b42542a7..0e6a288d9 100644 +--- a/ets2panda/ir/ts/tsBigintKeyword.cpp ++++ b/ets2panda/ir/ts/tsBigintKeyword.cpp +@@ -26,12 +26,7 @@ namespace ark::es2panda::ir { + void TSBigintKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSBigintKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsBooleanKeyword.cpp b/ets2panda/ir/ts/tsBooleanKeyword.cpp +index 4d5b6f018..bae3ac4ae 100644 +--- a/ets2panda/ir/ts/tsBooleanKeyword.cpp ++++ b/ets2panda/ir/ts/tsBooleanKeyword.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void TSBooleanKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSBooleanKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsConditionalType.cpp b/ets2panda/ir/ts/tsConditionalType.cpp +index 6a70708b5..6a166ea3f 100644 +--- a/ets2panda/ir/ts/tsConditionalType.cpp ++++ b/ets2panda/ir/ts/tsConditionalType.cpp +@@ -43,12 +43,8 @@ void TSConditionalType::TransformChildren(const NodeTransformer &cb, std::string + falseType_->SetTransformedNode(transformationName, transformedNode); + falseType_ = transformedNode->AsExpression(); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSConditionalType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsConstructorType.cpp b/ets2panda/ir/ts/tsConstructorType.cpp +index 681161a31..327034616 100644 +--- a/ets2panda/ir/ts/tsConstructorType.cpp ++++ b/ets2panda/ir/ts/tsConstructorType.cpp +@@ -26,12 +26,7 @@ namespace ark::es2panda::ir { + void TSConstructorType::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) + { + signature_.TransformChildren(cb, transformationName); +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSConstructorType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsEnumDeclaration.h b/ets2panda/ir/ts/tsEnumDeclaration.h +index f51091f6d..477f82d84 100644 +--- a/ets2panda/ir/ts/tsEnumDeclaration.h ++++ b/ets2panda/ir/ts/tsEnumDeclaration.h +@@ -120,11 +120,6 @@ public: + return decorators_; + } +  +- const ArenaVector *DecoratorsPtr() const override +- { +- return &Decorators(); +- } +- + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override + { + decorators_ = std::move(decorators); +diff --git a/ets2panda/ir/ts/tsFunctionType.cpp b/ets2panda/ir/ts/tsFunctionType.cpp +index ed1698e0a..89e4751ae 100644 +--- a/ets2panda/ir/ts/tsFunctionType.cpp ++++ b/ets2panda/ir/ts/tsFunctionType.cpp +@@ -27,12 +27,7 @@ namespace ark::es2panda::ir { + void TSFunctionType::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) + { + signature_.TransformChildren(cb, transformationName); +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSFunctionType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsImportType.cpp b/ets2panda/ir/ts/tsImportType.cpp +index 7854c7d3c..a0f981b89 100644 +--- a/ets2panda/ir/ts/tsImportType.cpp ++++ b/ets2panda/ir/ts/tsImportType.cpp +@@ -44,12 +44,8 @@ void TSImportType::TransformChildren(const NodeTransformer &cb, std::string_view + qualifier_ = transformedNode->AsExpression(); + } + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSImportType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsIndexedAccessType.cpp b/ets2panda/ir/ts/tsIndexedAccessType.cpp +index f2d897be6..e1e110231 100644 +--- a/ets2panda/ir/ts/tsIndexedAccessType.cpp ++++ b/ets2panda/ir/ts/tsIndexedAccessType.cpp +@@ -34,12 +34,8 @@ void TSIndexedAccessType::TransformChildren(const NodeTransformer &cb, std::stri + indexType_->SetTransformedNode(transformationName, transformedNode); + indexType_ = static_cast(transformedNode); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSIndexedAccessType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsInferType.cpp b/ets2panda/ir/ts/tsInferType.cpp +index 5db886b2e..dd9d1746d 100644 +--- a/ets2panda/ir/ts/tsInferType.cpp ++++ b/ets2panda/ir/ts/tsInferType.cpp +@@ -29,12 +29,8 @@ void TSInferType::TransformChildren(const NodeTransformer &cb, std::string_view + typeParam_->SetTransformedNode(transformationName, transformedNode); + typeParam_ = transformedNode->AsTSTypeParameter(); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSInferType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsInterfaceDeclaration.cpp b/ets2panda/ir/ts/tsInterfaceDeclaration.cpp +index 7f6fd875f..4195bfb98 100644 +--- a/ets2panda/ir/ts/tsInterfaceDeclaration.cpp ++++ b/ets2panda/ir/ts/tsInterfaceDeclaration.cpp +@@ -43,12 +43,7 @@ void TSInterfaceDeclaration::TransformChildren(const NodeTransformer &cb, std::s + } + } +  +- for (auto *&it : Annotations()) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); +  + if (auto *transformedNode = cb(id_); id_ != transformedNode) { + id_->SetTransformedNode(transformationName, transformedNode); +diff --git a/ets2panda/ir/ts/tsInterfaceDeclaration.h b/ets2panda/ir/ts/tsInterfaceDeclaration.h +index 202065911..c838c9010 100644 +--- a/ets2panda/ir/ts/tsInterfaceDeclaration.h ++++ b/ets2panda/ir/ts/tsInterfaceDeclaration.h +@@ -147,11 +147,6 @@ public: + return decorators_; + } +  +- const ArenaVector *DecoratorsPtr() const override +- { +- return &Decorators(); +- } +- + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override + { + decorators_ = std::move(decorators); +diff --git a/ets2panda/ir/ts/tsIntersectionType.cpp b/ets2panda/ir/ts/tsIntersectionType.cpp +index 75cf7834d..6dc630a18 100644 +--- a/ets2panda/ir/ts/tsIntersectionType.cpp ++++ b/ets2panda/ir/ts/tsIntersectionType.cpp +@@ -31,12 +31,8 @@ void TSIntersectionType::TransformChildren(const NodeTransformer &cb, std::strin + it = transformedNode->AsExpression(); + } + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSIntersectionType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsLiteralType.cpp b/ets2panda/ir/ts/tsLiteralType.cpp +index 25a998cc1..a679912bf 100644 +--- a/ets2panda/ir/ts/tsLiteralType.cpp ++++ b/ets2panda/ir/ts/tsLiteralType.cpp +@@ -28,12 +28,8 @@ void TSLiteralType::TransformChildren(const NodeTransformer &cb, std::string_vie + literal_->SetTransformedNode(transformationName, transformedNode); + literal_ = transformedNode->AsExpression(); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSLiteralType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsMappedType.cpp b/ets2panda/ir/ts/tsMappedType.cpp +index fef66f0e8..61da853b7 100644 +--- a/ets2panda/ir/ts/tsMappedType.cpp ++++ b/ets2panda/ir/ts/tsMappedType.cpp +@@ -37,12 +37,8 @@ void TSMappedType::TransformChildren(const NodeTransformer &cb, std::string_view + typeAnnotation_ = static_cast(transformedNode); + } + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSMappedType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsNamedTupleMember.cpp b/ets2panda/ir/ts/tsNamedTupleMember.cpp +index d07fb3d98..742f9e6cd 100644 +--- a/ets2panda/ir/ts/tsNamedTupleMember.cpp ++++ b/ets2panda/ir/ts/tsNamedTupleMember.cpp +@@ -34,12 +34,8 @@ void TSNamedTupleMember::TransformChildren(const NodeTransformer &cb, std::strin + elementType_->SetTransformedNode(transformationName, transformedNode); + elementType_ = static_cast(transformedNode); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSNamedTupleMember::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsNeverKeyword.cpp b/ets2panda/ir/ts/tsNeverKeyword.cpp +index 9b1386dca..a48751933 100644 +--- a/ets2panda/ir/ts/tsNeverKeyword.cpp ++++ b/ets2panda/ir/ts/tsNeverKeyword.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void TSNeverKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSNeverKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsNullKeyword.cpp b/ets2panda/ir/ts/tsNullKeyword.cpp +index d7050a9ff..6e089e142 100644 +--- a/ets2panda/ir/ts/tsNullKeyword.cpp ++++ b/ets2panda/ir/ts/tsNullKeyword.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void TSNullKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSNullKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsNumberKeyword.cpp b/ets2panda/ir/ts/tsNumberKeyword.cpp +index 9c9125def..afcee6e7b 100644 +--- a/ets2panda/ir/ts/tsNumberKeyword.cpp ++++ b/ets2panda/ir/ts/tsNumberKeyword.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void TSNumberKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSNumberKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsObjectKeyword.cpp b/ets2panda/ir/ts/tsObjectKeyword.cpp +index fd807caf0..3b4ea39d6 100644 +--- a/ets2panda/ir/ts/tsObjectKeyword.cpp ++++ b/ets2panda/ir/ts/tsObjectKeyword.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void TSObjectKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSObjectKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsParenthesizedType.cpp b/ets2panda/ir/ts/tsParenthesizedType.cpp +index 4ee640455..4608efb39 100644 +--- a/ets2panda/ir/ts/tsParenthesizedType.cpp ++++ b/ets2panda/ir/ts/tsParenthesizedType.cpp +@@ -28,12 +28,8 @@ void TSParenthesizedType::TransformChildren(const NodeTransformer &cb, std::stri + type_->SetTransformedNode(transformationName, transformedNode); + type_ = static_cast(transformedNode); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSParenthesizedType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsStringKeyword.cpp b/ets2panda/ir/ts/tsStringKeyword.cpp +index 825b446bc..be62a3400 100644 +--- a/ets2panda/ir/ts/tsStringKeyword.cpp ++++ b/ets2panda/ir/ts/tsStringKeyword.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void TSStringKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSStringKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsThisType.cpp b/ets2panda/ir/ts/tsThisType.cpp +index da5e36ad8..9af97be93 100644 +--- a/ets2panda/ir/ts/tsThisType.cpp ++++ b/ets2panda/ir/ts/tsThisType.cpp +@@ -24,12 +24,7 @@ namespace ark::es2panda::ir { + void TSThisType::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSThisType::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsTupleType.cpp b/ets2panda/ir/ts/tsTupleType.cpp +index cb69e8542..d98cbd162 100644 +--- a/ets2panda/ir/ts/tsTupleType.cpp ++++ b/ets2panda/ir/ts/tsTupleType.cpp +@@ -35,12 +35,8 @@ void TSTupleType::TransformChildren(const NodeTransformer &cb, std::string_view + it = static_cast(transformedNode); + } + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSTupleType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsTypeAliasDeclaration.h b/ets2panda/ir/ts/tsTypeAliasDeclaration.h +index 01a0959ff..42dbf2650 100644 +--- a/ets2panda/ir/ts/tsTypeAliasDeclaration.h ++++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.h +@@ -71,11 +71,6 @@ public: + return decorators_; + } +  +- const ArenaVector *DecoratorsPtr() const override +- { +- return &Decorators(); +- } +- + void SetTypeParameters(ir::TSTypeParameterDeclaration *typeParams) + { + typeParams_ = typeParams; +diff --git a/ets2panda/ir/ts/tsTypeLiteral.cpp b/ets2panda/ir/ts/tsTypeLiteral.cpp +index 418d5aa34..d13f7662c 100644 +--- a/ets2panda/ir/ts/tsTypeLiteral.cpp ++++ b/ets2panda/ir/ts/tsTypeLiteral.cpp +@@ -34,12 +34,8 @@ void TSTypeLiteral::TransformChildren(const NodeTransformer &cb, std::string_vie + it = transformedNode; + } + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSTypeLiteral::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsTypeOperator.cpp b/ets2panda/ir/ts/tsTypeOperator.cpp +index 7e66c0284..2fa2ad26a 100644 +--- a/ets2panda/ir/ts/tsTypeOperator.cpp ++++ b/ets2panda/ir/ts/tsTypeOperator.cpp +@@ -28,12 +28,8 @@ void TSTypeOperator::TransformChildren(const NodeTransformer &cb, std::string_vi + type_->SetTransformedNode(transformationName, transformedNode); + type_ = static_cast(transformedNode); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSTypeOperator::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsTypeParameter.cpp b/ets2panda/ir/ts/tsTypeParameter.cpp +index 65e18b0d8..56a1f3d6b 100644 +--- a/ets2panda/ir/ts/tsTypeParameter.cpp ++++ b/ets2panda/ir/ts/tsTypeParameter.cpp +@@ -45,12 +45,8 @@ void TSTypeParameter::TransformChildren(const NodeTransformer &cb, std::string_v + defaultType_ = static_cast(transformedNode); + } + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSTypeParameter::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsTypePredicate.cpp b/ets2panda/ir/ts/tsTypePredicate.cpp +index a1b253d85..0ab215842 100644 +--- a/ets2panda/ir/ts/tsTypePredicate.cpp ++++ b/ets2panda/ir/ts/tsTypePredicate.cpp +@@ -37,12 +37,8 @@ void TSTypePredicate::TransformChildren(const NodeTransformer &cb, std::string_v + typeAnnotation_ = static_cast(transformedNode); + } + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSTypePredicate::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsTypeQuery.cpp b/ets2panda/ir/ts/tsTypeQuery.cpp +index 70fe7b63f..5fa24495e 100644 +--- a/ets2panda/ir/ts/tsTypeQuery.cpp ++++ b/ets2panda/ir/ts/tsTypeQuery.cpp +@@ -29,12 +29,8 @@ void TSTypeQuery::TransformChildren(const NodeTransformer &cb, std::string_view + exprName_->SetTransformedNode(transformationName, transformedNode); + exprName_ = transformedNode->AsExpression(); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSTypeQuery::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsTypeReference.cpp b/ets2panda/ir/ts/tsTypeReference.cpp +index 459789b71..57b8f7d2a 100644 +--- a/ets2panda/ir/ts/tsTypeReference.cpp ++++ b/ets2panda/ir/ts/tsTypeReference.cpp +@@ -44,12 +44,8 @@ void TSTypeReference::TransformChildren(const NodeTransformer &cb, std::string_v + typeName_->SetTransformedNode(transformationName, transformedNode); + typeName_ = transformedNode->AsExpression(); + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSTypeReference::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsUndefinedKeyword.cpp b/ets2panda/ir/ts/tsUndefinedKeyword.cpp +index 4070aaf0b..5053cebca 100644 +--- a/ets2panda/ir/ts/tsUndefinedKeyword.cpp ++++ b/ets2panda/ir/ts/tsUndefinedKeyword.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void TSUndefinedKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSUndefinedKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsUnionType.cpp b/ets2panda/ir/ts/tsUnionType.cpp +index a25cccecc..aca8a8aa8 100644 +--- a/ets2panda/ir/ts/tsUnionType.cpp ++++ b/ets2panda/ir/ts/tsUnionType.cpp +@@ -30,12 +30,8 @@ void TSUnionType::TransformChildren(const NodeTransformer &cb, std::string_view + it = static_cast(transformedNode); + } + } +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ ++ TransformAnnotations(cb, transformationName); + } +  + void TSUnionType::Iterate(const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsUnknownKeyword.cpp b/ets2panda/ir/ts/tsUnknownKeyword.cpp +index f1daafebd..dd0bc5e84 100644 +--- a/ets2panda/ir/ts/tsUnknownKeyword.cpp ++++ b/ets2panda/ir/ts/tsUnknownKeyword.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void TSUnknownKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSUnknownKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/ts/tsVoidKeyword.cpp b/ets2panda/ir/ts/tsVoidKeyword.cpp +index d5a4341f2..ff09cc56d 100644 +--- a/ets2panda/ir/ts/tsVoidKeyword.cpp ++++ b/ets2panda/ir/ts/tsVoidKeyword.cpp +@@ -25,12 +25,7 @@ namespace ark::es2panda::ir { + void TSVoidKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb, + [[maybe_unused]] std::string_view const transformationName) + { +- for (auto *&it : VectorIterationGuard(Annotations())) { +- if (auto *transformedNode = cb(it); it != transformedNode) { +- it->SetTransformedNode(transformationName, transformedNode); +- it = transformedNode->AsAnnotationUsage(); +- } +- } ++ TransformAnnotations(cb, transformationName); + } +  + void TSVoidKeyword::Iterate([[maybe_unused]] const NodeTraverser &cb) const +diff --git a/ets2panda/ir/typed.h b/ets2panda/ir/typed.h +index 6a6b97a63..331a6c48e 100644 +--- a/ets2panda/ir/typed.h ++++ b/ets2panda/ir/typed.h +@@ -38,17 +38,20 @@ public: +  + [[nodiscard]] checker::Type const *TsType() const + { +- return tsType_; ++ return AstNode::GetHistoryNodeAs>()->tsType_; + } +  + [[nodiscard]] checker::Type *TsType() + { +- return tsType_; ++ return AstNode::GetHistoryNodeAs>()->tsType_; + } +  + checker::Type *SetTsType(checker::Type *tsType) noexcept + { +- return (tsType_ = tsType); ++ if (AstNode::GetHistoryNodeAs>()->TsType() != tsType) { ++ AstNode::GetOrCreateHistoryNodeAs>()->tsType_ = tsType; ++ } ++ return tsType; + } +  + bool IsTyped() const override +diff --git a/ets2panda/lexer/token/sourceLocation.h b/ets2panda/lexer/token/sourceLocation.h +index a150a8cfb..b6557e4d6 100644 +--- a/ets2panda/lexer/token/sourceLocation.h ++++ b/ets2panda/lexer/token/sourceLocation.h +@@ -52,6 +52,11 @@ public: +  + const parser::Program *Program() const; +  ++ bool operator!=(const SourcePosition &other) const ++ { ++ return index != other.index || line != other.line || program_ != other.program_; ++ } ++ + private: + const parser::Program *program_ {}; + }; +@@ -68,6 +73,11 @@ public: + SourcePosition start {}; + SourcePosition end {}; + // NOLINTEND(misc-non-private-member-variables-in-classes) ++ ++ bool operator!=(const SourceRange &other) const ++ { ++ return start != other.start || end != other.end; ++ } + }; +  + class SourceLocation { +diff --git a/ets2panda/parser/ETSparserNamespaces.cpp b/ets2panda/parser/ETSparserNamespaces.cpp +index af0e4d104..2ec07a76d 100644 +--- a/ets2panda/parser/ETSparserNamespaces.cpp ++++ b/ets2panda/parser/ETSparserNamespaces.cpp +@@ -82,7 +82,7 @@ ir::ETSModule *ETSParser::ParseNamespaceImp(ir::ModifierFlags flags) + if ((flags & ir::ModifierFlags::DECLARE) != 0) { + child->AddModifier(ir::ModifierFlags::DECLARE); + } +- parent->Statements().emplace_back(child); ++ parent->AddStatement(child); + parent = child; + } + ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE);