From ecbefb614a1a91c1f91e82111f15444126d0168a Mon Sep 17 00:00:00 2001 From: Maxim Bolshov Date: Wed, 27 Aug 2025 20:32:51 +0300 Subject: [PATCH 1/5] dump draft Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICWWVO?from=project-issue Signed-off-by: Maxim Bolshov Signed-off-by: Zhelyapov Aleksey Change-Id: Ica433bf28236d166ec6ec48e3e9142876df333a9 --- ets2panda/CMakeLists.txt | 20 +- ets2panda/arktsconfig.json | 49 +++++ ets2panda/checker/ets/helpers.cpp | 3 +- ets2panda/checker/ets/object.cpp | 5 +- .../checker/types/ets/etsFunctionType.cpp | 2 + ets2panda/compiler/core/compilerImpl.cpp | 56 ++++-- ets2panda/compiler/core/compilerImpl.h | 3 +- .../compiler/lowering/ets/declGenPhase.cpp | 4 +- ...defaultParametersInConstructorLowering.cpp | 1 - .../lowering/scopesInit/scopesInitPhase.cpp | 1 - ets2panda/ir/astNode.cpp | 13 +- ets2panda/ir/astNode.h | 7 +- ets2panda/ir/base/classDefinition.cpp | 12 +- ets2panda/ir/base/classProperty.cpp | 36 ++-- ets2panda/ir/base/methodDefinition.cpp | 93 ++++----- ets2panda/ir/base/methodDefinition.h | 2 - ets2panda/ir/base/overloadDeclaration.cpp | 2 +- ets2panda/ir/base/scriptFunction.cpp | 11 +- ets2panda/ir/ets/etsPackageDeclaration.h | 5 + ets2panda/ir/expressions/identifier.cpp | 5 +- ets2panda/ir/srcDump.cpp | 116 +++++++---- ets2panda/ir/srcDump.h | 186 +++++++++++++----- .../ir/statements/annotationDeclaration.cpp | 5 +- ets2panda/ir/ts/tsEnumDeclaration.cpp | 13 +- ets2panda/ir/ts/tsInterfaceDeclaration.cpp | 16 +- ets2panda/ir/ts/tsTypeAliasDeclaration.cpp | 10 +- ets2panda/parser/ETSparser.cpp | 4 +- ets2panda/public/es2panda_lib.cpp | 4 +- ets2panda/test/unit/declgen/CMakeLists.txt | 8 +- .../test/unit/declgen/ets/annotation.ets | 18 ++ .../declgen/ets/expected/annotation.d.ets | 8 + .../declgen/ets/expected/func_union.d.ets | 4 + .../unit/declgen/ets/expected/global.d.ets | 2 + .../declgen/ets/expected/namespace_ret.d.ets | 18 ++ .../unit/declgen/ets/expected/optional.d.ets | 9 + .../test/unit/declgen/ets/func_union.ets | 18 ++ ets2panda/test/unit/declgen/ets/global.ets | 1 + .../test/unit/declgen/ets/namespace_ret.ets | 21 ++ ets2panda/test/unit/declgen/ets/optional.ets | 19 ++ ets2panda/util/helpers.cpp | 16 +- 40 files changed, 601 insertions(+), 225 deletions(-) create mode 100644 ets2panda/arktsconfig.json create mode 100644 ets2panda/test/unit/declgen/ets/annotation.ets create mode 100644 ets2panda/test/unit/declgen/ets/expected/annotation.d.ets create mode 100644 ets2panda/test/unit/declgen/ets/expected/func_union.d.ets create mode 100644 ets2panda/test/unit/declgen/ets/expected/namespace_ret.d.ets create mode 100644 ets2panda/test/unit/declgen/ets/expected/optional.d.ets create mode 100644 ets2panda/test/unit/declgen/ets/func_union.ets create mode 100644 ets2panda/test/unit/declgen/ets/namespace_ret.ets create mode 100644 ets2panda/test/unit/declgen/ets/optional.ets diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 029703e32f..5100d34b30 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -55,12 +55,13 @@ endif() file(MAKE_DIRECTORY "${GENERATED_DIR}") if(PANDA_WITH_ETS) file(WRITE "${GENERATED_DIR}/arktsconfig.json" - "{\n" + "{\n" + " \"!NOTE!\": \"Generated from ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt\",\n" + "\n" + " \"compilerOptions\": {\n" " \"baseUrl\": \"${PANDA_ROOT}\",\n" " \"paths\": {\n" - " \"std\": [\"${STATIC_CORE}${DELIM}plugins${DELIM}ets${DELIM}stdlib${DELIM}std\"],\n" - " \"escompat\": [\"${STATIC_CORE}${DELIM}plugins${DELIM}ets${DELIM}stdlib${DELIM}escompat\"],\n" " \"@ohos.buffer\": [\"${STATIC_CORE}${DELIM}plugins${DELIM}ets${DELIM}sdk${DELIM}api${DELIM}@ohos.buffer.ets\"],\n" " \"@ohos.util.ArrayList\": [\"${STATIC_CORE}${DELIM}plugins${DELIM}ets${DELIM}sdk${DELIM}api${DELIM}@ohos.util.ArrayList.ets\"],\n" " \"@ohos.util.Deque\": [\"${STATIC_CORE}${DELIM}plugins${DELIM}ets${DELIM}sdk${DELIM}api${DELIM}@ohos.util.Deque.ets\"],\n" @@ -86,6 +87,19 @@ if(PANDA_WITH_ETS) " \"import_tests\": [\"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/import_tests\"]\n" " },\n" " \"dependencies\": {\n" + " \"std/core\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.core.d.ets\" },\n" + " \"std/math\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.math.d.ets\" },\n" + " \"std/math/consts\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.math.consts.d.ets\" },\n" + " \"std/containers\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.containers.d.ets\" },\n" + " \"std/interop/js\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.interop.js.d.ets\" },\n" + " \"std/time\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.time.d.ets\" },\n" + " \"std/debug\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.debug.d.ets\" },\n" + " \"std/debug/concurrency\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.debug.concurrency.d.ets\" },\n" + " \"std/testing\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.testing.d.ets\" },\n" + " \"std/concurrency\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.concurrency.d.ets\" },\n" + " \"std/annotations\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.annotations.d.ets\" },\n" + " \"std/interop\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.interop.d.ets\" },\n" + " \"escompat\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}escompat.d.ets\" },\n" " \"dynamic_import_tests\": {\"language\": \"js\", \"ohmUrl\": \"dynamic_import_tests\"},\n" " \"dynamic_import_tests/modules/instanceof\": {\"language\": \"js\", \"path\": \"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/dynamic_import_tests/modules/instanceof.ets\", \"ohmUrl\": \"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/dynamic_import_tests/modules/instanceof.ets\"},\n" " \"dynamic_import_tests/modules/module\": {\"language\": \"js\", \"path\": \"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/dynamic_import_tests/modules/module.ets\", \"ohmUrl\": \"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/dynamic_import_tests/modules/module.ets\"}\n" diff --git a/ets2panda/arktsconfig.json b/ets2panda/arktsconfig.json new file mode 100644 index 0000000000..4a73a0169e --- /dev/null +++ b/ets2panda/arktsconfig.json @@ -0,0 +1,49 @@ +{ + "compilerOptions": { + "baseUrl": "/home/mbolshov/workspace/panda/static_core", + "paths": { + "std/core": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.core.d.ets"], + "std/math": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.math.d.ets"], + "std/math/consts": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.math.consts.d.ets"], + "std/containers": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.containers.d.ets"], + "std/interop/js": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.interop.js.d.ets"], + "std/time": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.time.d.ets"], + "std/debug": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.debug.d.ets"], + "std/debug/concurrency": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.debug.concurrency.d.ets"], + "std/testing": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.testing.d.ets"], + "std/concurrency": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.concurrency.d.ets"], + "std/annotations": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.annotations.d.ets"], + "std/interop": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/std.interop.d.ets"], + "escompat": ["/home/mbolshov/workspace/panda/builds/static_core-fastverify/etsstdlib/escompat.d.ets"], + "@ohos.buffer": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.buffer.ets"], + "@ohos.util.ArrayList": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.ArrayList.ets"], + "@ohos.util.Deque": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.Deque.ets"], + "@ohos.util.HashMap": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.HashMap.ets"], + "@ohos.util.HashSet": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.HashSet.ets"], + "@ohos.util.json": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.json.ets"], + "@ohos.util.LightWeightMap": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.LightWeightMap.ets"], + "@ohos.util.LightWeightSet": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.LightWeightSet.ets"], + "@ohos.util.LinkedList": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.LinkedList.ets"], + "@ohos.util.List": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.List.ets"], + "@ohos.util.PlainArray": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.PlainArray.ets"], + "@ohos.util.Queue": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.Queue.ets"], + "@ohos.util.Stack": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.Stack.ets"], + "@ohos.util.stream": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.stream.ets"], + "@ohos.util": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.ets"], + "@ohos.util.TreeMap": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.TreeMap.ets"], + "@ohos.util.TreeSet": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.util.TreeSet.ets"], + "@ohos.uri": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.uri.ets"], + "@ohos.url": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.url.ets"], + "@ohos.xml": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.xml.ets"], + "@ohos.base": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/api/@ohos.base.ets"], + "@arkts.math.Decimal": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/arkts/@arkts.math.Decimal.ets"], + "@arkts.collections": ["/home/mbolshov/workspace/panda/static_core/plugins/ets/sdk/arkts/@arkts.collections.ets"], + "import_tests": ["/home/mbolshov/workspace/arkcompiler_ets_frontend/ets2panda/test/parser/ets/import_tests"] + }, + "dependencies": { + "dynamic_import_tests": {"language": "js", "ohmUrl": "dynamic_import_tests"}, + "dynamic_import_tests/modules/instanceof": {"language": "js", "path": "/home/mbolshov/workspace/arkcompiler_ets_frontend/ets2panda/test/parser/ets/dynamic_import_tests/modules/instanceof.ets", "ohmUrl": "/home/mbolshov/workspace/arkcompiler_ets_frontend/ets2panda/test/parser/ets/dynamic_import_tests/modules/instanceof.ets"}, + "dynamic_import_tests/modules/module": {"language": "js", "path": "/home/mbolshov/workspace/arkcompiler_ets_frontend/ets2panda/test/parser/ets/dynamic_import_tests/modules/module.ets", "ohmUrl": "/home/mbolshov/workspace/arkcompiler_ets_frontend/ets2panda/test/parser/ets/dynamic_import_tests/modules/module.ets"} + } + } +} diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 7af150985b..37759c919a 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -3252,7 +3252,8 @@ void ETSChecker::ImportNamespaceObjectTypeAddReExportType(ir::ETSImportDeclarati Type *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importDecl, ir::Identifier *ident) { - auto importPath = importDecl->IsPureDynamic() ? importDecl->DeclPath() : importDecl->ResolvedSource(); + auto importPath = + importDecl->ImportMetadata().HasSpecifiedDeclPath() ? importDecl->DeclPath() : importDecl->ResolvedSource(); parser::Program *program = SelectEntryOrExternalProgram(static_cast(VarBinder()), importPath); if (program == nullptr) { diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index a9e62345ac..e769f1718a 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -1357,7 +1357,10 @@ void ETSChecker::CheckClassDefinition(ir::ClassDefinition *classDef) // NOTE(gogabr): temporary, until we have proper bridges, see #16485 // Don't check overriding for synthetic functional classes. if ((static_cast(classDef)->Modifiers() & ir::ModifierFlags::FUNCTIONAL) == 0) { - ValidateOverriding(classType, classDef->Start()); + // NOTE(dkofanov): Overriding can't be checked for classes from 'd.ets'. + if (!classDef->IsDeclare()) { + ValidateOverriding(classType, classDef->Start()); + } } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) diff --git a/ets2panda/checker/types/ets/etsFunctionType.cpp b/ets2panda/checker/types/ets/etsFunctionType.cpp index 669ab5d1ed..463cd6800f 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.cpp +++ b/ets2panda/checker/types/ets/etsFunctionType.cpp @@ -176,7 +176,9 @@ void ETSFunctionType::AddCallSignature(Signature *signature) void ETSFunctionType::ToString(std::stringstream &ss, bool precise) const { + ss << "("; callSignatures_[0]->ToString(ss, nullptr, false, precise); + ss << ")"; } // Method types do not participate in most type relations diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 01ee4a204c..4050e25892 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -107,8 +107,8 @@ static bool CheckOptionsBeforePhase(const util::Options &options, const parser:: return options.GetExitBeforePhase() == name; } -void HandleGenerateDecl(const parser::Program &program, util::DiagnosticEngine &diagnosticEngine, - const std::string &outputPath) +static void WriteStringToFile(std::string &&str, util::DiagnosticEngine &diagnosticEngine, + const std::string &outputPath) { std::ofstream outFile(outputPath); if (!outFile.is_open()) { @@ -116,15 +116,26 @@ void HandleGenerateDecl(const parser::Program &program, util::DiagnosticEngine & lexer::SourcePosition()); return; } - std::string result = program.Ast()->DumpDecl(); - result = "'use static'\n" + result; - - outFile << result; + outFile << str; outFile.close(); // Add generated declaration to the cache auto &declarationCache = parser::DeclarationCache::Instance(); - declarationCache.AddDeclaration(outputPath, std::make_shared(std::move(result))); + declarationCache.AddDeclaration(outputPath, std::make_shared(std::move(str))); +} + +void HandleGenerateDecl(const parser::Program &program, public_lib::Context *context, const std::string &outputPath) +{ + WriteStringToFile(program.Ast()->DumpDecl(context), *context->diagnosticEngine, outputPath); +} + +std::string ResolveDeclsOutputPath(const util::Options &options) +{ + if (!options.WasSetGenerateDeclPath()) { + return ark::os::RemoveExtension(util::BaseName(options.SourceFileName())).append(".d.ets"); + } else { + return options.GetGenerateDeclPath(); + } } static bool CheckOptionsAfterPhase(const util::Options &options, const parser::Program &program, @@ -143,6 +154,29 @@ static bool CheckOptionsAfterPhase(const util::Options &options, const parser::P return options.GetExitAfterPhase() == name; } +static void GenDeclsForStdlib(public_lib::Context &context, const util::Options &options, + const parser::Program &program) +{ + for (const auto &[moduleName, extPrograms] : program.ExternalSources()) { + ir::Declgen dg {&context}; + ir::SrcDumper dumper {&dg}; + dumper.Add("'use static'\n"); + for (const auto *extProg : extPrograms) { + extProg->Ast()->Dump(&dumper); + } + dumper.GetDeclgen()->Run(); + std::string moduleDecl = dumper.Str(); + std::string path = moduleName.Mutf8() + ".d.ets"; + if (options.WasSetGenerateDeclPath()) { + // NOTE: "/" at the end needed because of bug in GetParentDir + auto parentDir = ark::os::GetParentDir(options.GetGenerateDeclPath() + "/"); + ark::os::CreateDirectories(parentDir); + path = parentDir + "/" + path; + } + WriteStringToFile(std::move(moduleDecl), *context.diagnosticEngine, path); + } +} + // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP, G.FUD.05) solid logic static bool RunVerifierAndPhases(public_lib::Context &context, parser::Program &program) { @@ -180,13 +214,11 @@ static bool RunVerifierAndPhases(public_lib::Context &context, parser::Program & } if (options.IsGenerateDeclEnabled() && name == compiler::CheckerPhase::NAME) { - std::string path; - if (!options.WasSetGenerateDeclPath()) { - path = ark::os::RemoveExtension(util::BaseName(options.SourceFileName())).append(".d.ets"); + if (options.IsGenStdlib()) { + GenDeclsForStdlib(context, options, program); } else { - path = options.GetGenerateDeclPath(); + HandleGenerateDecl(program, &context, ResolveDeclsOutputPath(options)); } - HandleGenerateDecl(program, *context.diagnosticEngine, path); } } diff --git a/ets2panda/compiler/core/compilerImpl.h b/ets2panda/compiler/core/compilerImpl.h index d60ffa77ca..c065f3d0dc 100644 --- a/ets2panda/compiler/core/compilerImpl.h +++ b/ets2panda/compiler/core/compilerImpl.h @@ -25,8 +25,7 @@ struct Program; namespace ark::es2panda::compiler { class CompileQueue; -void HandleGenerateDecl(const parser::Program &program, util::DiagnosticEngine &diagnosticEngine, - const std::string &outputPath); +void HandleGenerateDecl(const parser::Program &program, public_lib::Context *context, const std::string &outputPath); class CompilationUnit { public: diff --git a/ets2panda/compiler/lowering/ets/declGenPhase.cpp b/ets2panda/compiler/lowering/ets/declGenPhase.cpp index 5a2913c27e..85f273288a 100644 --- a/ets2panda/compiler/lowering/ets/declGenPhase.cpp +++ b/ets2panda/compiler/lowering/ets/declGenPhase.cpp @@ -15,8 +15,10 @@ #include "declGenPhase.h" +#include #include "checker/ETSchecker.h" #include "compiler/lowering/util.h" +#include "ir/ets/etsPackageDeclaration.h" namespace ark::es2panda::compiler { @@ -33,7 +35,7 @@ bool DeclGenPhase::PerformForModule(public_lib::Context *ctx, parser::Program *p auto *allocator = ctx->Allocator(); // Arena cause we want declaration be life until codegen happens - auto *declaration = allocator->New(program->Ast()->DumpDecl(), allocator->Adapter()); + auto *declaration = allocator->New(program->Ast()->DumpDecl(ctx), allocator->Adapter()); ES2PANDA_ASSERT(declaration != nullptr); auto *const annoUsageIdent = checker->AllocNode(MODULE_DECLARATION_NAME, checker->Allocator()); diff --git a/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp b/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp index 7f0b016fd0..dca94d1802 100644 --- a/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp +++ b/ets2panda/compiler/lowering/ets/defaultParametersInConstructorLowering.cpp @@ -256,7 +256,6 @@ static void ClearOptionalParameters(public_lib::Context *ctx, ir::ScriptFunction // NOTE (DZ): temporary solution until node history starts working properly param->SetOriginalNode(oldParam); oldParam->SetParent(param); - param->SetOriginalNode(oldParam); } ES2PANDA_ASSERT(!param->AsETSParameterExpression()->IsOptional()); } diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 29e91fdc6d..160f7d2717 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -1442,7 +1442,6 @@ void InitScopesPhaseETS::VisitClassProperty(ir::ClassProperty *classProp) if (classProp->TypeAnnotation() != nullptr && !classProp->TypeAnnotation()->IsETSPrimitiveType()) { --(pos.index); } - LogDiagnostic(diagnostic::CONST_WITHOUT_INIT, pos); } AddOrGetDecl(VarBinder(), name, classProp, classProp->Key()->Start(), name, classProp); } else if (classProp->IsReadonly()) { diff --git a/ets2panda/ir/astNode.cpp b/ets2panda/ir/astNode.cpp index 8114961153..eeeee71837 100644 --- a/ets2panda/ir/astNode.cpp +++ b/ets2panda/ir/astNode.cpp @@ -141,14 +141,19 @@ std::string AstNode::DumpJSON() const std::string AstNode::DumpEtsSrc() const { - ir::SrcDumper dumper {this}; + ir::SrcDumper dumper {}; + Dump(&dumper); return dumper.Str(); } -std::string AstNode::DumpDecl() const +std::string AstNode::DumpDecl(public_lib::Context *context) const { - ir::SrcDumper dumper {this, true}; - dumper.Run(); + Declgen dg {context}; + + ir::SrcDumper dumper {&dg}; + dumper.Add("'use static'\n"); + Dump(&dumper); + dumper.GetDeclgen()->Run(); return dumper.Str(); } diff --git a/ets2panda/ir/astNode.h b/ets2panda/ir/astNode.h index f6bbfea987..15dcfc1523 100644 --- a/ets2panda/ir/astNode.h +++ b/ets2panda/ir/astNode.h @@ -24,6 +24,10 @@ #include "lexer/token/sourceLocation.h" #include "util/es2pandaMacros.h" +namespace ark::es2panda::public_lib { +struct Context; +} // namespace ark::es2panda::public_lib + namespace ark::es2panda::compiler { class PandaGen; class ETSGen; @@ -115,6 +119,7 @@ class AstNodeHistory; class AstDumper; class Expression; class SrcDumper; +class Declgen; class Statement; class ClassElement; template @@ -668,7 +673,7 @@ public: std::string DumpJSON() const; std::string DumpEtsSrc() const; - std::string DumpDecl() const; + std::string DumpDecl(public_lib::Context *context) const; virtual void Dump(ir::AstDumper *dumper) const = 0; virtual void Dump(ir::SrcDumper *dumper) const = 0; diff --git a/ets2panda/ir/base/classDefinition.cpp b/ets2panda/ir/base/classDefinition.cpp index 0c02f92ba3..0fe6251eb1 100644 --- a/ets2panda/ir/base/classDefinition.cpp +++ b/ets2panda/ir/base/classDefinition.cpp @@ -382,7 +382,7 @@ void ClassDefinition::DumpPrefix(ir::SrcDumper *dumper) const } if (dumper->IsDeclgen()) { - dumper->TryDeclareAmbientContext(); + dumper->GetDeclgen()->TryDeclareAmbientContext(dumper); } else if (IsDeclare()) { dumper->Add("declare "); } @@ -406,11 +406,9 @@ void ClassDefinition::DumpPrefix(ir::SrcDumper *dumper) const bool ClassDefinition::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const { - if (!dumper->IsDeclgen()) { - return false; - } + ES2PANDA_ASSERT(dumper->IsDeclgen()); - if (dumper->IsIndirectDepPhase()) { + if (dumper->GetDeclgen()->IsPostDumpIndirectDepsPhase()) { return false; } @@ -419,7 +417,7 @@ bool ClassDefinition::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const } const auto className = ident_->Name().Mutf8(); - dumper->AddNode(className, this); + dumper->GetDeclgen()->AddNode(className, this); return true; } @@ -439,7 +437,7 @@ void ClassDefinition::Dump(ir::SrcDumper *dumper) const ES2PANDA_ASSERT(ident_ != nullptr); - if (RegisterUnexportedForDeclGen(dumper)) { + if (dumper->IsDeclgen() && !IsNamespaceTransformed() && RegisterUnexportedForDeclGen(dumper)) { return; } diff --git a/ets2panda/ir/base/classProperty.cpp b/ets2panda/ir/base/classProperty.cpp index ae5a6082d5..16268874a3 100644 --- a/ets2panda/ir/base/classProperty.cpp +++ b/ets2panda/ir/base/classProperty.cpp @@ -20,6 +20,7 @@ #include "compiler/core/ETSGen.h" #include "compiler/core/pandagen.h" #include "compiler/lowering/util.h" +#include "public/public.h" namespace ark::es2panda::ir { @@ -100,7 +101,10 @@ void ClassProperty::DumpModifiers(ir::SrcDumper *dumper) const ES2PANDA_ASSERT(key_); if (compiler::HasGlobalClassParent(this)) { - if (key_->Parent()->IsConst()) { + if (IsExported()) { + dumper->Add("export "); + } + if (IsConst()) { dumper->Add("const "); } else { dumper->Add("let "); @@ -159,27 +163,20 @@ void ClassProperty::DumpPrefix(ir::SrcDumper *dumper) const void ClassProperty::DumpCheckerTypeForDeclGen(ir::SrcDumper *dumper) const { - if (!dumper->IsDeclgen()) { - return; - } + ES2PANDA_ASSERT(dumper->IsDeclgen()); if (TsType() == nullptr) { return; } - auto typeStr = TsType()->ToString(); dumper->Add(": "); - dumper->Add(typeStr); - - dumper->PushTask([dumper, typeStr] { dumper->DumpNode(typeStr); }); + dumper->GetDeclgen()->Dump(dumper, TsType()); } bool ClassProperty::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const { ES2PANDA_ASSERT(key_); - if (!dumper->IsDeclgen()) { - return false; - } + ES2PANDA_ASSERT(dumper->IsDeclgen()); auto name = key_->AsIdentifier()->Name().Mutf8(); if (name.rfind('#', 0) == 0) { @@ -194,7 +191,7 @@ bool ClassProperty::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const return false; } - if (dumper->IsIndirectDepPhase()) { + if (dumper->GetDeclgen()->IsPostDumpIndirectDepsPhase()) { return false; } @@ -202,16 +199,19 @@ bool ClassProperty::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const return false; } - dumper->AddNode(name, this); + dumper->GetDeclgen()->AddNode(name, this); return true; } void ClassProperty::Dump(ir::SrcDumper *dumper) const { - if (dumper->IsDeclgen() && IsInternal()) { + bool isNamespaceTransformed = + Parent()->IsClassDefinition() && Parent()->AsClassDefinition()->IsNamespaceTransformed(); + // For declgen dump only if explicitly marked as export or it is public property of class (not namespace or module) + if (dumper->IsDeclgen() && !(IsExported() || IsDefaultExported() || (!isNamespaceTransformed && IsPublic()))) { return; } - if (RegisterUnexportedForDeclGen(dumper)) { + if (dumper->IsDeclgen() && RegisterUnexportedForDeclGen(dumper)) { return; } DumpPrefix(dumper); @@ -228,13 +228,13 @@ void ClassProperty::Dump(ir::SrcDumper *dumper) const dumper->Add("!"); } - if (typeAnnotation_ != nullptr && !dumper->IsDeclgen()) { + if (typeAnnotation_ != nullptr) { dumper->Add(": "); TypeAnnotation()->Dump(dumper); + } else if (dumper->IsDeclgen()) { + DumpCheckerTypeForDeclGen(dumper); } - DumpCheckerTypeForDeclGen(dumper); - if (value_ != nullptr) { if (!dumper->IsDeclgen() || Parent()->IsAnnotationDeclaration()) { dumper->Add(" = "); diff --git a/ets2panda/ir/base/methodDefinition.cpp b/ets2panda/ir/base/methodDefinition.cpp index 4cfd0e4284..641ae3541e 100644 --- a/ets2panda/ir/base/methodDefinition.cpp +++ b/ets2panda/ir/base/methodDefinition.cpp @@ -167,35 +167,34 @@ void MethodDefinition::Dump(ir::AstDumper *dumper) const {"overloads", Overloads()}}); } -void MethodDefinition::DumpModifierPrefix(ir::SrcDumper *dumper) const +static void DumpModifierPrefix(const ir::MethodDefinition *m, ir::SrcDumper *dumper) { - if (compiler::HasGlobalClassParent(this)) { - return; - } - if (IsStatic()) { + ES2PANDA_ASSERT(!compiler::HasGlobalClassParent(m)); + if (m->IsStatic()) { dumper->Add("static "); } - if (IsAbstract() && !(Parent()->IsTSInterfaceBody() || - (BaseOverloadMethod() != nullptr && BaseOverloadMethod()->Parent()->IsTSInterfaceBody()))) { + if (m->IsAbstract() && + !(m->Parent()->IsTSInterfaceBody() || + (m->BaseOverloadMethod() != nullptr && m->BaseOverloadMethod()->Parent()->IsTSInterfaceBody()))) { dumper->Add("abstract "); } - if (IsFinal()) { + if (m->IsFinal()) { dumper->Add("final "); } - if (IsNative()) { + if (m->IsNative()) { dumper->Add("native "); } - if (IsAsync() && !dumper->IsDeclgen()) { + if (m->IsAsync() && !dumper->IsDeclgen()) { dumper->Add("async "); } - if (IsOverride()) { + if (m->IsOverride()) { dumper->Add("override "); } - if (IsGetter()) { + if (m->IsGetter()) { dumper->Add("get "); - } else if (IsSetter()) { + } else if (m->IsSetter()) { dumper->Add("set "); } } @@ -213,39 +212,39 @@ static bool IsNamespaceTransformed(const MethodDefinition *method) return false; } -void MethodDefinition::DumpPrefix(ir::SrcDumper *dumper) const +static void DumpPrefix(const ir::MethodDefinition *m, ir::SrcDumper *dumper) { - bool global = compiler::HasGlobalClassParent(this); - if (global || IsNamespaceTransformed(this)) { - if (IsExported()) { + bool global = compiler::HasGlobalClassParent(m); + if (global || IsNamespaceTransformed(m)) { + if (m->IsExported()) { dumper->Add("export "); } - if (IsDefaultExported()) { + if (m->IsDefaultExported()) { dumper->Add("export default "); } if (dumper->IsDeclgen()) { if (global) { dumper->Add("declare "); } else { - dumper->TryDeclareAmbientContext(); + dumper->GetDeclgen()->TryDeclareAmbientContext(dumper); } } dumper->Add("function "); return; } - if (Parent() != nullptr && Parent()->IsClassDefinition() && !Parent()->AsClassDefinition()->IsLocal()) { - if (IsPrivate()) { + if (m->Parent() != nullptr && m->Parent()->IsClassDefinition() && !m->Parent()->AsClassDefinition()->IsLocal()) { + if (m->IsPrivate()) { dumper->Add("private "); - } else if (IsProtected()) { + } else if (m->IsProtected()) { dumper->Add("protected "); - } else if (IsInternal()) { + } else if (m->IsInternal() && !dumper->IsDeclgen()) { dumper->Add("internal "); - } else { + } else if (!dumper->IsDeclgen()) { dumper->Add("public "); } } - DumpModifierPrefix(dumper); + DumpModifierPrefix(m, dumper); } bool MethodDefinition::FilterForDeclGen() const @@ -254,6 +253,10 @@ bool MethodDefinition::FilterForDeclGen() const return false; } + if (Function()->IsSynthetic()) { + return true; + } + if (compiler::HasGlobalClassParent(this) && !key_->Parent()->IsExported() && !key_->Parent()->IsDefaultExported()) { return true; } @@ -273,29 +276,18 @@ bool MethodDefinition::FilterForDeclGen() const return true; } - if (name == compiler::Signatures::GET_INDEX_METHOD || name == compiler::Signatures::SET_INDEX_METHOD) { - return true; - } - - if (IsPrivate() || IsInternal()) { - return true; - } - return false; } -void MethodDefinition::Dump(ir::SrcDumper *dumper) const +static void DumpSingleOverload(const ir::MethodDefinition *m, ir::SrcDumper *dumper) { - if (dumper->IsDeclgen() && FilterForDeclGen()) { + if (compiler::HasGlobalClassParent(m) && m->Id() != nullptr && + m->Id()->Name().Is(compiler::Signatures::INIT_METHOD)) { + m->Function()->Body()->Dump(dumper); return; } - if (compiler::HasGlobalClassParent(this) && Id() != nullptr && Id()->Name().Is(compiler::Signatures::INIT_METHOD)) { - Function()->Body()->Dump(dumper); - return; - } - - auto value = Value(); + auto value = m->Value(); if (value->AsFunctionExpression()->Function()->HasAnnotations()) { for (auto *anno : value->AsFunctionExpression()->Function()->Annotations()) { // NOTE(zhelyapov): workaround, see #26031 @@ -305,14 +297,14 @@ void MethodDefinition::Dump(ir::SrcDumper *dumper) const } } - DumpPrefix(dumper); + DumpPrefix(m, dumper); - if (IsConstructor() && - !(Key()->IsIdentifier() && Key()->AsIdentifier()->Name().Is(compiler::Signatures::CONSTRUCTOR_NAME))) { + if (m->IsConstructor() && + !(m->Key()->IsIdentifier() && m->Key()->AsIdentifier()->Name().Is(compiler::Signatures::CONSTRUCTOR_NAME))) { dumper->Add(std::string(compiler::Signatures::CONSTRUCTOR_NAME) + " "); } - auto key = Key(); + auto key = m->Key(); if (key != nullptr) { key->Dump(dumper); } @@ -320,6 +312,17 @@ void MethodDefinition::Dump(ir::SrcDumper *dumper) const if (value != nullptr) { value->Dump(dumper); } +} + +void MethodDefinition::Dump(ir::SrcDumper *dumper) const +{ + if (dumper->IsDeclgen() && FilterForDeclGen()) { + return; + } + + if (!dumper->IsDeclgen() || !IsPrivate()) { + DumpSingleOverload(this, dumper); + } for (auto method : Overloads()) { method->Dump(dumper); diff --git a/ets2panda/ir/base/methodDefinition.h b/ets2panda/ir/base/methodDefinition.h index e8ea9b58ba..3fbd62fbbf 100644 --- a/ets2panda/ir/base/methodDefinition.h +++ b/ets2panda/ir/base/methodDefinition.h @@ -245,9 +245,7 @@ protected: void CopyTo(AstNode *other) const override; private: - void DumpPrefix(ir::SrcDumper *dumper) const; void ResetOverloads(); - void DumpModifierPrefix(ir::SrcDumper *dumper) const; bool DumpNamespaceForDeclGen(ir::SrcDumper *dumper) const; void DumpPrefixForDeclGen(ir::SrcDumper *dumper) const; bool FilterForDeclGen() const; diff --git a/ets2panda/ir/base/overloadDeclaration.cpp b/ets2panda/ir/base/overloadDeclaration.cpp index 7af8f592ff..efae9e7200 100644 --- a/ets2panda/ir/base/overloadDeclaration.cpp +++ b/ets2panda/ir/base/overloadDeclaration.cpp @@ -131,4 +131,4 @@ void OverloadDeclaration::CopyTo(AstNode *other) const ClassElement::CopyTo(other); } -} // namespace ark::es2panda::ir \ No newline at end of file +} // namespace ark::es2panda::ir diff --git a/ets2panda/ir/base/scriptFunction.cpp b/ets2panda/ir/base/scriptFunction.cpp index 0cd1d4a6cf..b21230ed99 100644 --- a/ets2panda/ir/base/scriptFunction.cpp +++ b/ets2panda/ir/base/scriptFunction.cpp @@ -288,9 +288,7 @@ void ScriptFunction::Dump(ir::AstDumper *dumper) const void ScriptFunction::DumpCheckerTypeForDeclGen(ir::SrcDumper *dumper) const { - if (!dumper->IsDeclgen()) { - return; - } + ES2PANDA_ASSERT(dumper->IsDeclgen()); if (IsConstructor()) { return; @@ -312,7 +310,7 @@ void ScriptFunction::DumpCheckerTypeForDeclGen(ir::SrcDumper *dumper) const dumper->Add(": "); dumper->Add(typeStr); - dumper->PushTask([dumper, typeStr] { dumper->DumpNode(typeStr); }); + dumper->GetDeclgen()->PushTask([dumper, typeStr] { dumper->GetDeclgen()->DumpNode(dumper, typeStr); }); } void ScriptFunction::Dump(ir::SrcDumper *dumper) const @@ -330,11 +328,12 @@ void ScriptFunction::Dump(ir::SrcDumper *dumper) const } } dumper->Add(")"); - if (ReturnTypeAnnotation() != nullptr && !dumper->IsDeclgen()) { + if (ReturnTypeAnnotation() != nullptr) { dumper->Add(": "); ReturnTypeAnnotation()->Dump(dumper); + } else if (dumper->IsDeclgen()) { + DumpCheckerTypeForDeclGen(dumper); } - DumpCheckerTypeForDeclGen(dumper); if (dumper->IsDeclgen()) { dumper->Add(";"); dumper->Endl(); diff --git a/ets2panda/ir/ets/etsPackageDeclaration.h b/ets2panda/ir/ets/etsPackageDeclaration.h index 4ceb1e5383..db1e54213a 100644 --- a/ets2panda/ir/ets/etsPackageDeclaration.h +++ b/ets2panda/ir/ets/etsPackageDeclaration.h @@ -50,6 +50,11 @@ public: v->Accept(this); } + const ir::Expression *Name() const + { + return name_; + } + private: ir::Expression *name_; }; diff --git a/ets2panda/ir/expressions/identifier.cpp b/ets2panda/ir/expressions/identifier.cpp index 050fd78b37..833348dd66 100644 --- a/ets2panda/ir/expressions/identifier.cpp +++ b/ets2panda/ir/expressions/identifier.cpp @@ -144,7 +144,10 @@ void Identifier::Dump(ir::SrcDumper *dumper) const dumper->Add("?"); } - dumper->PushTask([dumper, name = std::string(name_)] { dumper->DumpNode(name); }); + if (dumper->IsDeclgen()) { + dumper->GetDeclgen()->PushTask( + [dumper, name = std::string(name_)] { dumper->GetDeclgen()->DumpNode(dumper, name); }); + } } void Identifier::Compile(compiler::PandaGen *pg) const diff --git a/ets2panda/ir/srcDump.cpp b/ets2panda/ir/srcDump.cpp index d87e3dd148..053a6e8c7b 100644 --- a/ets2panda/ir/srcDump.cpp +++ b/ets2panda/ir/srcDump.cpp @@ -21,20 +21,16 @@ #include #include #include +#include + +#include + +#include "util/helpers.h" #include #include - namespace ark::es2panda::ir { -SrcDumper::SrcDumper(const ir::AstNode *node) -{ - node->Dump(this); -} - -SrcDumper::SrcDumper(const ir::AstNode *node, bool isDeclgen) : isDeclgen_(isDeclgen) -{ - node->Dump(this); -} +SrcDumper::SrcDumper(Declgen *dg) : dg_(dg) {} void SrcDumper::IncrIndent() { @@ -133,34 +129,73 @@ void SrcDumper::Add(double d) bool SrcDumper::IsDeclgen() const { - return isDeclgen_; + return GetDeclgen() != nullptr; } -void SrcDumper::DumpVariant(NodeVariant &node) +Declgen *SrcDumper::GetDeclgen() const { - std::visit( - [this](auto &&value) { - using T = std::decay_t; - if constexpr (!std::is_same_v) { - if constexpr (std::is_pointer_v) { - DumpNodeIfPointer(value); - } - } - }, - node); + return dg_; } -template -void SrcDumper::DumpNodeIfPointer(T *value) -{ - if (value) { - isIndirectDepPhase_ = true; - value->Dump(this); - isIndirectDepPhase_ = false; +struct PostDumper { + explicit PostDumper(SrcDumper *dumper) : dumper_ {dumper} {} + + void operator()(const ir::AstNode *node) + { + auto g1 = dumper_->GetDeclgen()->BuildAmbientContextGuard(); + auto g2 = dumper_->GetDeclgen()->BuildPostDumpIndirectDepsPhaseLockGuard(); + dumper_->GetDeclgen()->SetPostDumpIndirectDepsPhase(); + auto namespacesCount = ReconstructNamespaces(node); + node->Dump(dumper_); + DestroyNamespaces(namespacesCount); } -} -void SrcDumper::DumpNode(const std::string &key) + size_t ReconstructNamespaces(const ir::AstNode *node) + { + std::vector nsChain; + + auto getImmediateNamespace = [](const ir::AstNode *n) { + auto classDef = ark::es2panda::util::Helpers::FindAncestorGivenByType(n, ir::AstNodeType::CLASS_DEFINITION); + if ((classDef != nullptr) && classDef->AsClassDefinition()->IsNamespaceTransformed()) { + return classDef; + } + return static_cast(nullptr); + }; + for (auto classDef = getImmediateNamespace(node); classDef != nullptr; + classDef = getImmediateNamespace(classDef)) { + ES2PANDA_ASSERT(classDef->AsClassDefinition()->IsNamespaceTransformed()); + nsChain.push_back(classDef->AsClassDefinition()); + } + + for (auto it = nsChain.rbegin(); it != nsChain.rend(); ++it) { + auto ns = *it; + if (ns->IsExported()) { + dumper_->Add("export "); + } + dumper_->GetDeclgen()->TryDeclareAmbientContext(dumper_); + dumper_->Add("namespace " + ns->Ident()->Name().Mutf8() + " {"); + } + dumper_->Add("\n"); + return nsChain.size(); + } + + void DestroyNamespaces(size_t namespacesCount) + { + std::string nsClose(namespacesCount, '}'); + nsClose.append("\n"); + dumper_->Add(nsClose); + } + + void operator()([[maybe_unused]] std::monostate) + { + ES2PANDA_UNREACHABLE(); + } + +private: + SrcDumper *dumper_ {}; +}; + +void Declgen::DumpNode(SrcDumper *dumper, const std::string &key) { auto it = unExportNode_.find(key); if (it == unExportNode_.end()) { @@ -170,10 +205,25 @@ void SrcDumper::DumpNode(const std::string &key) NodeVariant node = it->second; unExportNode_.erase(it); - DumpVariant(node); + std::visit(PostDumper {dumper}, node); +} + +void Declgen::Dump(ir::SrcDumper *dumper, const checker::Type *type) +{ + auto typeStr = type->ToString(); + auto *parser = GetCtx()->parser->AsETSParser(); + parser->CreateFormattedTypeAnnotation(typeStr)->Dump(dumper); +} + +void Declgen::TryDeclareAmbientContext(SrcDumper *srcDumper) +{ + if (!ambientDeclarationLock_.IsAcquired()) { + ambientDeclarationLock_.Acquire(); + srcDumper->Add("declare "); + } } -void SrcDumper::Run() +void Declgen::Run() { while (!taskQueue_.empty()) { auto task = std::move(taskQueue_.front()); diff --git a/ets2panda/ir/srcDump.h b/ets2panda/ir/srcDump.h index 59bbf15500..5d86edfd32 100644 --- a/ets2panda/ir/srcDump.h +++ b/ets2panda/ir/srcDump.h @@ -34,79 +34,108 @@ class ClassProperty; class TSInterfaceDeclaration; class TSEnumDeclaration; -using NodeVariant = - std::variant; +class SrcDumper; -class SrcDumper { +class Declgen { public: - explicit SrcDumper(const ir::AstNode *node); - explicit SrcDumper(const ir::AstNode *node, bool isDeclgen); + using NodeVariant = + std::variant; - void Add(const std::string &str); - void Add(int8_t i); - void Add(int16_t i); - void Add(int32_t i); - void Add(int64_t l); - void Add(float f); - void Add(double d); + Declgen(public_lib::Context *ctx) : ctx_ {ctx} {} - std::string Str() const; + void DumpNode(SrcDumper *dumper, const std::string &key); - void IncrIndent(); - void DecrIndent(); - void Endl(size_t num = 1); + void Dump(SrcDumper *dumper, const checker::Type *type); - bool IsDeclgen() const; - void DumpVariant(NodeVariant &node); - void DumpNode(const std::string &key); + class Lock { + private: + class Releaser { + public: + NO_COPY_SEMANTIC(Releaser); + + explicit Releaser(Releaser &&other) : lock_ {other.lock_}, prevAcquired_ {other.prevAcquired_} + { + other.lock_ = nullptr; + } + + Releaser() : lock_ {nullptr}, prevAcquired_ {false} {} + explicit Releaser(Lock *lock) : lock_ {lock}, prevAcquired_ {lock->acquired_} + { + if (lock_ != nullptr) { + lock_->releasers_++; + } + } + + ~Releaser() + { + if (lock_ != nullptr) { + lock_->acquired_ = prevAcquired_; + lock_->releasers_--; + } + } + + private: + Lock *lock_; + bool prevAcquired_; + }; - class AmbientContextGuard { public: - explicit AmbientContextGuard(bool *ambientDeclPtr) : ambientDeclPtr_ {ambientDeclPtr}, prev_ {*ambientDeclPtr} + void Acquire() + { + ES2PANDA_ASSERT(releasers_ != 0); + acquired_ = true; + } + + bool IsAcquired() { + return acquired_; } - ~AmbientContextGuard() + [[nodiscard]] auto BuildReleaser() { - *ambientDeclPtr_ = prev_; + return Releaser {this}; + } + + [[nodiscard]] static auto BuildEmptyReleaser() + { + return Releaser {}; } private: - bool *ambientDeclPtr_; - bool prev_; + bool acquired_ {false}; + size_t releasers_ {}; }; - [[nodiscard]] AmbientContextGuard BuildAmbientContextGuard() + + // Ambient + auto BuildAmbientContextGuard() { - return AmbientContextGuard {&ambientWasDeclared_}; + return ambientDeclarationLock_.BuildReleaser(); } - void TryDeclareAmbientContext() + + void TryDeclareAmbientContext(SrcDumper *srcDumper); + + // Postdump + auto BuildPostDumpIndirectDepsPhaseLockGuard() { - ES2PANDA_ASSERT(IsDeclgen()); - if (!ambientWasDeclared_) { - Add("declare "); - ambientWasDeclared_ = true; - } + return postDumpIndirectDepsPhaseLock_.BuildReleaser(); } - template - void DumpNodeIfPointer(T *value); - - template - void AddNode(const std::string &key, T *value) + void SetPostDumpIndirectDepsPhase() { - unExportNode_[key] = NodeVariant(value); + postDumpIndirectDepsPhaseLock_.Acquire(); } - void RemoveNode(const std::string &key) + bool IsPostDumpIndirectDepsPhase() { - unExportNode_.erase(key); + return postDumpIndirectDepsPhaseLock_.IsAcquired(); } - bool IsIndirectDepPhase() const + template + void AddNode(const std::string &key, T *value) { - return isIndirectDepPhase_; + unExportNode_[key] = NodeVariant(value); } template @@ -117,16 +146,73 @@ public: void Run(); + auto GetCtx() const + { + return ctx_; + } + +private: + public_lib::Context *ctx_; + + // track 'declare' keyword: + Lock ambientDeclarationLock_; + + /* "post-dump": */ + Lock postDumpIndirectDepsPhaseLock_; + // queued nodes that need to be post-dumped: + std::queue> taskQueue_ {}; + // a dictionary with "hidden" nodes that may be dumped at post-dump. + // NOTE(dkofanov): it should be aware of names collision, 'string' is to be changed to 'Variable *'. + std::unordered_map unExportNode_ {}; +}; + +class SrcDumper { +public: + // Delete after the bindings problem solved: + explicit SrcDumper([[maybe_unused]] const ir::AstNode *node) + { + ES2PANDA_UNREACHABLE(); + } + explicit SrcDumper([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] bool isDeclgen) + { + ES2PANDA_UNREACHABLE(); + } + + explicit SrcDumper(Declgen *dg = nullptr); + + void Add(const std::string &str); + void Add(int8_t i); + void Add(int16_t i); + void Add(int32_t i); + void Add(int64_t l); + void Add(float f); + void Add(double d); + + std::string Str() const; + + void IncrIndent(); + void DecrIndent(); + void Endl(size_t num = 1); + + bool IsDeclgen() const; + Declgen *GetDeclgen() const; + + auto BuildAmbientContextGuard() + { + if (IsDeclgen()) { + return GetDeclgen()->BuildAmbientContextGuard(); + } + return Declgen::Lock::BuildEmptyReleaser(); + } + private: std::stringstream ss_; std::string indent_; - bool isDeclgen_ = false; - bool isIndirectDepPhase_ = false; - bool ambientWasDeclared_ = false; - std::unordered_map unExportNode_; - std::queue> taskQueue_; + /* declgen-specific: */ + Declgen *dg_; }; + } // namespace ark::es2panda::ir #endif // ES2PANDA_IR_SRCDUMP_H diff --git a/ets2panda/ir/statements/annotationDeclaration.cpp b/ets2panda/ir/statements/annotationDeclaration.cpp index ef585a3083..d3a4c0e51a 100644 --- a/ets2panda/ir/statements/annotationDeclaration.cpp +++ b/ets2panda/ir/statements/annotationDeclaration.cpp @@ -105,13 +105,14 @@ void AnnotationDeclaration::Dump(ir::AstDumper *dumper) const void AnnotationDeclaration::Dump(ir::SrcDumper *dumper) const { + auto guard = dumper->BuildAmbientContextGuard(); DumpAnnotations(dumper); ES2PANDA_ASSERT(Expr() != nullptr); if (IsExported()) { dumper->Add("export "); } - if (IsDeclare() || dumper->IsDeclgen()) { - dumper->Add("declare "); + if (dumper->IsDeclgen()) { + dumper->GetDeclgen()->TryDeclareAmbientContext(dumper); } dumper->Add("@interface "); Expr()->Dump(dumper); diff --git a/ets2panda/ir/ts/tsEnumDeclaration.cpp b/ets2panda/ir/ts/tsEnumDeclaration.cpp index 453a98a8b3..e51a7d2896 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.cpp +++ b/ets2panda/ir/ts/tsEnumDeclaration.cpp @@ -79,11 +79,9 @@ void TSEnumDeclaration::Dump(ir::AstDumper *dumper) const bool TSEnumDeclaration::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const { - if (!dumper->IsDeclgen()) { - return false; - } + ES2PANDA_ASSERT(dumper->IsDeclgen()); - if (dumper->IsIndirectDepPhase()) { + if (dumper->GetDeclgen()->IsPostDumpIndirectDepsPhase()) { return false; } @@ -92,15 +90,16 @@ bool TSEnumDeclaration::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) cons } auto name = key_->AsIdentifier()->Name().Mutf8(); - dumper->AddNode(name, this); + dumper->GetDeclgen()->AddNode(name, this); return true; } void TSEnumDeclaration::Dump(ir::SrcDumper *dumper) const { + auto guard = dumper->BuildAmbientContextGuard(); ES2PANDA_ASSERT(isConst_ == false); ES2PANDA_ASSERT(key_ != nullptr); - if (RegisterUnexportedForDeclGen(dumper)) { + if (dumper->IsDeclgen() && RegisterUnexportedForDeclGen(dumper)) { return; } if (key_->Parent()->IsExported() && dumper->IsDeclgen()) { @@ -109,7 +108,7 @@ void TSEnumDeclaration::Dump(ir::SrcDumper *dumper) const dumper->Add("export default "); } if (dumper->IsDeclgen()) { - dumper->TryDeclareAmbientContext(); + dumper->GetDeclgen()->TryDeclareAmbientContext(dumper); } else if (IsDeclare()) { dumper->Add("declare "); } diff --git a/ets2panda/ir/ts/tsInterfaceDeclaration.cpp b/ets2panda/ir/ts/tsInterfaceDeclaration.cpp index fdc64a4685..70393d55f4 100644 --- a/ets2panda/ir/ts/tsInterfaceDeclaration.cpp +++ b/ets2panda/ir/ts/tsInterfaceDeclaration.cpp @@ -156,11 +156,10 @@ void TSInterfaceDeclaration::Dump(ir::AstDumper *dumper) const bool TSInterfaceDeclaration::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const { - if (!dumper->IsDeclgen()) { - return false; - } + ASSERT(false); + ES2PANDA_ASSERT(dumper->IsDeclgen()); - if (dumper->IsIndirectDepPhase()) { + if (dumper->GetDeclgen()->IsPostDumpIndirectDepsPhase()) { return false; } @@ -169,17 +168,18 @@ bool TSInterfaceDeclaration::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) } auto name = id_->Name().Mutf8(); - dumper->AddNode(name, this); + dumper->GetDeclgen()->AddNode(name, this); return true; } void TSInterfaceDeclaration::Dump(ir::SrcDumper *dumper) const { + auto guard = dumper->BuildAmbientContextGuard(); ES2PANDA_ASSERT(id_); if (!id_->Parent()->IsDefaultExported() && !id_->Parent()->IsExported() && dumper->IsDeclgen() && - !dumper->IsIndirectDepPhase()) { + !dumper->GetDeclgen()->IsPostDumpIndirectDepsPhase()) { auto name = id_->Name().Mutf8(); - dumper->AddNode(name, this); + dumper->GetDeclgen()->AddNode(name, this); return; } DumpAnnotations(dumper); @@ -189,7 +189,7 @@ void TSInterfaceDeclaration::Dump(ir::SrcDumper *dumper) const dumper->Add("export default "); } if (dumper->IsDeclgen()) { - dumper->TryDeclareAmbientContext(); + dumper->GetDeclgen()->TryDeclareAmbientContext(dumper); } else if (IsDeclare()) { dumper->Add("declare "); } diff --git a/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp b/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp index d19433ee84..6dc8357c0b 100644 --- a/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp +++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp @@ -92,11 +92,9 @@ void TSTypeAliasDeclaration::Dump(ir::AstDumper *dumper) const bool TSTypeAliasDeclaration::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) const { - if (!dumper->IsDeclgen()) { - return false; - } + ES2PANDA_ASSERT(dumper->IsDeclgen()); - if (dumper->IsIndirectDepPhase()) { + if (dumper->GetDeclgen()->IsPostDumpIndirectDepsPhase()) { return false; } @@ -105,14 +103,14 @@ bool TSTypeAliasDeclaration::RegisterUnexportedForDeclGen(ir::SrcDumper *dumper) } auto name = id_->Name().Mutf8(); - dumper->AddNode(name, this); + dumper->GetDeclgen()->AddNode(name, this); return true; } void TSTypeAliasDeclaration::Dump(ir::SrcDumper *dumper) const { ES2PANDA_ASSERT(id_); - if (RegisterUnexportedForDeclGen(dumper)) { + if (dumper->IsDeclgen() && RegisterUnexportedForDeclGen(dumper)) { return; } DumpAnnotations(dumper); diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 0e9894d3ff..d55d4cde79 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -316,7 +316,9 @@ void ETSParser::ParseParseListElement(const util::ImportPathManager::ParseInfo & const auto &importData = parseListElem.importData; auto src = importData.HasSpecifiedDeclPath() ? importData.declPath : importData.resolvedSource; ES2PANDA_ASSERT(!extSrc.empty()); - SourceFile sf {src, extSrc, importData.resolvedSource, false, importData.HasSpecifiedDeclPath()}; + + bool isDynamic = importData.lang != Language::Id::ETS; + SourceFile sf {src, extSrc, importData.resolvedSource, false, isDynamic}; sf.isExternalSourceImport = importData.IsExternalSourceImport(); parser::Program *newProg = ParseSource(sf); ES2PANDA_ASSERT(newProg != nullptr); diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index ea052d5e3d..c43c986596 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -1320,7 +1320,7 @@ __attribute__((unused)) static bool HandleMultiFileMode(Context *ctxImpl, const } if (prog->FileName().Mutf8() == outputStem) { - compiler::HandleGenerateDecl(*prog, *ctxImpl->diagnosticEngine, outputPath); + compiler::HandleGenerateDecl(*prog, ctxImpl, outputPath); return !ctxImpl->diagnosticEngine->IsAnyError(); } } @@ -1345,7 +1345,7 @@ extern "C" __attribute__((unused)) int GenerateStaticDeclarationsFromContext(es2 } // Single file mode - compiler::HandleGenerateDecl(*ctxImpl->parserProgram, *ctxImpl->diagnosticEngine, outputPath); + compiler::HandleGenerateDecl(*ctxImpl->parserProgram, ctxImpl, outputPath); return ctxImpl->diagnosticEngine->IsAnyError() ? 1 : 0; } diff --git a/ets2panda/test/unit/declgen/CMakeLists.txt b/ets2panda/test/unit/declgen/CMakeLists.txt index 0bf413a536..a740b2ac15 100644 --- a/ets2panda/test/unit/declgen/CMakeLists.txt +++ b/ets2panda/test/unit/declgen/CMakeLists.txt @@ -88,11 +88,15 @@ endforeach() add_custom_target(declgen-ets-test) set(ETS_TESTS - test pckg/test + annotation + func_union global - overload + namespace_ret nested + optional + overload + test ) set(WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR}/ets) diff --git a/ets2panda/test/unit/declgen/ets/annotation.ets b/ets2panda/test/unit/declgen/ets/annotation.ets new file mode 100644 index 0000000000..691f1cfaa0 --- /dev/null +++ b/ets2panda/test/unit/declgen/ets/annotation.ets @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export @interface Anno {} + +export class A {} diff --git a/ets2panda/test/unit/declgen/ets/expected/annotation.d.ets b/ets2panda/test/unit/declgen/ets/expected/annotation.d.ets new file mode 100644 index 0000000000..37d702da3a --- /dev/null +++ b/ets2panda/test/unit/declgen/ets/expected/annotation.d.ets @@ -0,0 +1,8 @@ +'use static' + +export declare @interface Anno {} +export declare class A { + public constructor(); + +} + diff --git a/ets2panda/test/unit/declgen/ets/expected/func_union.d.ets b/ets2panda/test/unit/declgen/ets/expected/func_union.d.ets new file mode 100644 index 0000000000..66dd859ac7 --- /dev/null +++ b/ets2panda/test/unit/declgen/ets/expected/func_union.d.ets @@ -0,0 +1,4 @@ +'use static' + +export declare function foo(): ((()=> void) | undefined); + diff --git a/ets2panda/test/unit/declgen/ets/expected/global.d.ets b/ets2panda/test/unit/declgen/ets/expected/global.d.ets index 6a93f35244..e4aad17c9a 100644 --- a/ets2panda/test/unit/declgen/ets/expected/global.d.ets +++ b/ets2panda/test/unit/declgen/ets/expected/global.d.ets @@ -1,5 +1,7 @@ 'use static' +export const P: Double; + export declare function foo(): void; export default declare function baz(): void; diff --git a/ets2panda/test/unit/declgen/ets/expected/namespace_ret.d.ets b/ets2panda/test/unit/declgen/ets/expected/namespace_ret.d.ets new file mode 100644 index 0000000000..69c420431c --- /dev/null +++ b/ets2panda/test/unit/declgen/ets/expected/namespace_ret.d.ets @@ -0,0 +1,18 @@ +'use static' + +export declare class ValueImpl extends NS.Value { + public getValue(): NS.Value; + + public constructor(); + +} + +export declare namespace NS { + + export class Value { + public constructor(); + + } + +} + diff --git a/ets2panda/test/unit/declgen/ets/expected/optional.d.ets b/ets2panda/test/unit/declgen/ets/expected/optional.d.ets new file mode 100644 index 0000000000..e377d04c66 --- /dev/null +++ b/ets2panda/test/unit/declgen/ets/expected/optional.d.ets @@ -0,0 +1,9 @@ +'use static' + +export declare class C { + public constructor(b: (boolean | undefined)); + + public foo(b?: boolean): void; + +} + diff --git a/ets2panda/test/unit/declgen/ets/func_union.ets b/ets2panda/test/unit/declgen/ets/func_union.ets new file mode 100644 index 0000000000..ddec0a9006 --- /dev/null +++ b/ets2panda/test/unit/declgen/ets/func_union.ets @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export function foo(): (() => void)|undefined { + return undefined +} diff --git a/ets2panda/test/unit/declgen/ets/global.ets b/ets2panda/test/unit/declgen/ets/global.ets index dbe7d6655e..447872a82e 100644 --- a/ets2panda/test/unit/declgen/ets/global.ets +++ b/ets2panda/test/unit/declgen/ets/global.ets @@ -16,3 +16,4 @@ export function foo() {} export default function baz() {} function bar() {} +export const P: number = 3.1 diff --git a/ets2panda/test/unit/declgen/ets/namespace_ret.ets b/ets2panda/test/unit/declgen/ets/namespace_ret.ets new file mode 100644 index 0000000000..13055cc63b --- /dev/null +++ b/ets2panda/test/unit/declgen/ets/namespace_ret.ets @@ -0,0 +1,21 @@ +/* + * 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. + */ + +export namespace NS { + export class Value {} +} +export class ValueImpl extends NS.Value { + getValue(): NS.Value {return new NS.Value} +} diff --git a/ets2panda/test/unit/declgen/ets/optional.ets b/ets2panda/test/unit/declgen/ets/optional.ets new file mode 100644 index 0000000000..0f091f32a1 --- /dev/null +++ b/ets2panda/test/unit/declgen/ets/optional.ets @@ -0,0 +1,19 @@ +/* + * 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. + */ + +export class C { + constructor(b?: boolean) {} + foo(b?: boolean){} +} diff --git a/ets2panda/util/helpers.cpp b/ets2panda/util/helpers.cpp index fe9e9b5e32..acaacc550c 100644 --- a/ets2panda/util/helpers.cpp +++ b/ets2panda/util/helpers.cpp @@ -711,9 +711,11 @@ std::pair Helpers::SplitSignature(std::strin std::vector const &Helpers::StdLib() { - static std::vector stdlib {"std/core", "std/math", "std/containers", "std/interop/js", - "std/time", "std/debug", "std/debug/concurrency", "std/testing", - "escompat", "std/concurrency", "std/annotations", "std/interop"}; + static std::vector stdlib { + "std/core", "std/math", "std/containers", "std/interop/js", + "std/time", "std/debug", "std/debug/concurrency", "std/testing", + "escompat", "std/concurrency", "std/annotations", "std/interop", + "std/math/consts"}; return stdlib; } @@ -770,6 +772,10 @@ bool Helpers::IsNumericGlobalBuiltIn(checker::Type *type, checker::ETSChecker *c bool Helpers::IsStdLib(const parser::Program *program) { + if (program->AbsoluteName().Utf8().find("stdlib") != std::string_view::npos) { + return true; + } + // NOTE(rsipka): early check: if program is not in a package then it is not part of the stdlib either if (!program->IsPackage()) { return false; @@ -779,10 +785,6 @@ bool Helpers::IsStdLib(const parser::Program *program) std::replace(fileFolder.begin(), fileFolder.end(), *compiler::Signatures::METHOD_SEPARATOR.begin(), *compiler::Signatures::NAMESPACE_SEPARATOR.begin()); - if (fileFolder == "std/math/consts") { - return true; - } - auto const &stdlib = StdLib(); return std::count(stdlib.begin(), stdlib.end(), fileFolder) != 0; } -- Gitee From ad136c880f07e30272c38c564a0ba9da9e673d34 Mon Sep 17 00:00:00 2001 From: lirismankarina Date: Fri, 22 Aug 2025 19:56:23 +0300 Subject: [PATCH 2/5] [es2panda] Parsing from single .abc via offset Issue: [es2panda] Parsing from single .abc via offset https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICUN2Y Reason: Need to make parsing from abc file faster Description: update of abc file and parsing from es2panda Tests: ninja all tests Signed-off-by: lirismankarina --- ets2panda/BUILD.gn | 5 -- ets2panda/CMakeLists.txt | 2 +- ets2panda/aot/BUILD.gn | 1 - ets2panda/bindings/BUILD.gn | 1 - ets2panda/util/importPathManager.cpp | 83 ++++++++++++++++++---------- ets2panda/util/importPathManager.h | 2 + 6 files changed, 58 insertions(+), 36 deletions(-) diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 02cb5bc5a8..bf31837fa5 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -1168,7 +1168,6 @@ if (ark_standalone_build || ark_static_standalone_build) { "$ark_root/assembler:arkassembler_public_config", "$ark_root/libpandabase:arkbase_public_config", "$ark_root/libarkfile:arkfile_public_config", - "$ark_root/abc2program:arkts_abc2program_public_config", ] } @@ -1222,7 +1221,6 @@ ohos_source_set("libes2panda_frontend_static") { ":isa_gen_es2panda_isa_h", ] external_deps = [ - "runtime_core:libarktsabc2program_package", "runtime_core:libarktsassembler_package", "runtime_core:libarktsbase_package", "runtime_core:libarktscompiler_package", @@ -1238,7 +1236,6 @@ ohos_source_set("libes2panda_frontend_static") { external_deps += [ "icu:static_icui18n", "icu:static_icuuc", - "runtime_core:arkts_abc2program_public_headers", "runtime_core:assembler_headers", "runtime_core:libpandabase_headers", "runtime_core:libpandafile_headers", @@ -1305,14 +1302,12 @@ ohos_source_set("libes2panda_public_frontend_static") { } external_deps = [ - "runtime_core:libarktsabc2program_package", "runtime_core:libarktsbytecodeopt_package", sdk_libc_secshared_dep, ] if (ark_standalone_build || ark_static_standalone_build) { deps += [ - "$ark_root/abc2program:libarktsabc2program_package", "$ark_root/assembler:libarktsassembler", "$ark_root/bytecode_optimizer:libarktsbytecodeopt_package", "$ark_root/compiler:libarktscompiler", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 5100d34b30..7768e37106 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -729,7 +729,7 @@ endif() panda_target_link_libraries(es2panda-lib PUBLIC arkbase hmicuuc.z - PRIVATE arkassembler arkdisassembler arkfile abc2program + PRIVATE arkassembler arkdisassembler arkfile ) if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.1) OR diff --git a/ets2panda/aot/BUILD.gn b/ets2panda/aot/BUILD.gn index a861d7d1a4..f8cd444d5b 100644 --- a/ets2panda/aot/BUILD.gn +++ b/ets2panda/aot/BUILD.gn @@ -76,7 +76,6 @@ ohos_executable("ets2panda") { "runtime_core:libarktsbytecodeopt_package", "runtime_core:libarktscompiler_package", "runtime_core:libarktsfile_package", - "runtime_core:libarktsabc2program_package", sdk_libc_secshared_dep, ] diff --git a/ets2panda/bindings/BUILD.gn b/ets2panda/bindings/BUILD.gn index 79e0c7eddf..54cf5ca4fa 100644 --- a/ets2panda/bindings/BUILD.gn +++ b/ets2panda/bindings/BUILD.gn @@ -61,7 +61,6 @@ shared_library("ts_bindings") { if (ark_standalone_build) { deps += [ "$ark_root/bytecode_optimizer:libarktsbytecodeopt_frontend_static", - "$ark_root/abc2program:arkts_abc2program_static", "$ark_third_party_root/bounds_checking_function:libsec_shared", ] include_dirs += [ "//third_party/node/src" ] diff --git a/ets2panda/util/importPathManager.cpp b/ets2panda/util/importPathManager.cpp index 854890ffa4..a7f93fb25e 100644 --- a/ets2panda/util/importPathManager.cpp +++ b/ets2panda/util/importPathManager.cpp @@ -25,9 +25,12 @@ #include "parser/program/program.h" #include "ir/expressions/literals/stringLiteral.h" -#include "abc2program_driver.h" #include "compiler/lowering/ets/declGenPhase.h" + +#include "libarkfile/class_data_accessor-inl.h" +#include "libarkfile/file-inl.h" #include "libpandabase/utils/logger.h" +#include #ifdef USE_UNIX_SYSCALL #include @@ -62,6 +65,15 @@ static bool IsAbsolute(const std::string &path) #endif // ARKTSCONFIG_USE_FILESYSTEM } +void RemoveEscapedNewlines(std::string &s) +{ + std::string pattern = "\\n"; + size_t pos = 0; + while ((pos = s.find(pattern, pos)) != std::string::npos) { + s.erase(pos, pattern.size()); + } +} + void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) { ES2PANDA_ASSERT(!IsAbsolute(std::string(importData.resolvedSource))); @@ -82,34 +94,49 @@ void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) // process .abc "path" in "dependencies" ES2PANDA_ASSERT(Helpers::EndsWith(std::string(externalModuleImportData.Path()), ".abc")); importData.importFlags |= ImportFlags::EXTERNAL_BINARY_IMPORT; - abc2program::Abc2ProgramDriver driver; - driver.Compile(std::string {externalModuleImportData.Path()}); - pandasm::Program &prog = driver.GetProgram(); - // NOTE(itrubachev): support binary file after ark_link #26280 - auto etsGlobalRecord = std::find_if(prog.recordTable.begin(), prog.recordTable.end(), [](auto &record) { - auto annotations = record.second.metadata->GetAnnotations(); - auto moduleDeclAnno = std::find_if(annotations.begin(), annotations.end(), [](auto &anno) { - return anno.GetName() == compiler::DeclGenPhase::MODULE_DECLARATION_ANNOTATION; - }); - return moduleDeclAnno != annotations.end(); - }); - ES2PANDA_ASSERT(etsGlobalRecord != prog.recordTable.end()); - // rely on the following mangling: .ETSGLOBAL - auto etsGlobalSuffix = std::string(".") + std::string(compiler::Signatures::ETS_GLOBAL); - ES2PANDA_ASSERT(Helpers::EndsWith(etsGlobalRecord->second.name, etsGlobalSuffix)); - auto moduleName = - etsGlobalRecord->second.name.substr(0, etsGlobalRecord->second.name.size() - etsGlobalSuffix.size()); - importData.ohmUrl = util::UString(moduleName, allocator_).View().Utf8(); - - auto annotations = etsGlobalRecord->second.metadata->GetAnnotations(); - auto moduleDeclarationAnno = std::find_if(annotations.begin(), annotations.end(), [](auto &anno) { - return anno.GetName() == compiler::DeclGenPhase::MODULE_DECLARATION_ANNOTATION; - }); - ES2PANDA_ASSERT(moduleDeclarationAnno != annotations.end()); - auto declText = util::UString( - moduleDeclarationAnno->GetElements()[0].GetValue()->GetAsScalar()->GetValue(), allocator_); - importData.declText = declText.View().Utf8(); + auto pf = panda_file::OpenPandaFile(std::string {externalModuleImportData.Path()}); + if (!pf) { + LOG(FATAL, ES2PANDA) << "Failed to load a provided abc file: " << externalModuleImportData.Path(); + } + + // take the classes that contain ModuleDeclaration annotation onlyy + for (auto id : pf->GetExported()) { + panda_file::File::EntityId classId(id); + panda_file::ClassDataAccessor cda(*pf, classId); + + // processing annotation to extract string with declaration text + auto success = + cda.EnumerateAnnotation(ANNOTATION_MODULE_DECLARATION.data(), + [&importData, &pf, this](panda_file::AnnotationDataAccessor &annotationAccessor) { + auto elem = annotationAccessor.GetElement(0); + auto value = elem.GetScalarValue(); + const auto idAnno = value.Get(); + std::stringstream ss; + ss << StringDataToString(pf->GetStringData(idAnno)); + std::string declText = ss.str(); + if (!declText.empty()) { + RemoveEscapedNewlines(declText); + importData.declText = util::UString(declText, allocator_).View().Utf8(); + return true; + } + return false; + }); + if (!success) { + return; + } + // processing name to get ohmUrl + std::string name = utf::Mutf8AsCString(pf->GetStringData(classId).data); + auto type = pandasm::Type::FromDescriptor(name); + type = pandasm::Type(type.GetNameWithoutRank(), type.GetRank()); + auto recordName = type.GetPandasmName(); + + // rely on the following mangling: .ETSGLOBAL + auto etsGlobalSuffix = std::string(".") + std::string(compiler::Signatures::ETS_GLOBAL); + ES2PANDA_ASSERT(Helpers::EndsWith(recordName, etsGlobalSuffix)); + auto moduleName = recordName.substr(0, recordName.size() - etsGlobalSuffix.size()); + importData.ohmUrl = util::UString(moduleName, allocator_).View().Utf8(); + } } // If needed, the result of this function can be cached diff --git a/ets2panda/util/importPathManager.h b/ets2panda/util/importPathManager.h index e966725157..588d91e54d 100644 --- a/ets2panda/util/importPathManager.h +++ b/ets2panda/util/importPathManager.h @@ -77,6 +77,8 @@ struct ModuleInfo { class ImportPathManager { public: static constexpr auto DUMMY_PATH = "dummy_path"; // CC-OFF(G.NAM.03-CPP) project code style + static constexpr std::string_view ANNOTATION_MODULE_DECLARATION = + "Lstd/annotations/ModuleDeclaration;"; // CC-OFF(G.NAM.03-CPP) project code style struct ImportMetadata { // NOLINTBEGIN(misc-non-private-member-variables-in-classes) ImportFlags importFlags {}; -- Gitee From f25864bdcbbf41391cc11447c5cb13a29445bed7 Mon Sep 17 00:00:00 2001 From: lirismankarina Date: Wed, 3 Sep 2025 20:32:35 +0300 Subject: [PATCH 3/5] [es2panda] Parsing stdlib from d.ets that were taken from etssstdlib.abc Signed-off-by: lirismankarina --- .../compiler/lowering/ets/declGenPhase.cpp | 2 +- ets2panda/util/arktsconfig.h | 4 +- ets2panda/util/importPathManager.cpp | 239 ++++++++++++++++-- ets2panda/util/importPathManager.h | 3 + 4 files changed, 218 insertions(+), 30 deletions(-) diff --git a/ets2panda/compiler/lowering/ets/declGenPhase.cpp b/ets2panda/compiler/lowering/ets/declGenPhase.cpp index 85f273288a..a147e12f0b 100644 --- a/ets2panda/compiler/lowering/ets/declGenPhase.cpp +++ b/ets2panda/compiler/lowering/ets/declGenPhase.cpp @@ -26,7 +26,7 @@ constexpr std::string_view MODULE_DECLARATION_NAME {"ModuleDeclaration"}; bool DeclGenPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { - if (!ctx->config->options->IsEmitDeclaration()) { + if (!ctx->config->options->IsEmitDeclaration() && !ctx->config->options->IsGenStdlib()) { return true; } diff --git a/ets2panda/util/arktsconfig.h b/ets2panda/util/arktsconfig.h index eeb613ccb2..7fe3f8b38b 100644 --- a/ets2panda/util/arktsconfig.h +++ b/ets2panda/util/arktsconfig.h @@ -167,11 +167,11 @@ public: { return useUrl_; } - const PathsMap &Paths() const + PathsMap &Paths() { return paths_; } - const std::map &Dependencies() const + std::map &Dependencies() { return dependencies_; } diff --git a/ets2panda/util/importPathManager.cpp b/ets2panda/util/importPathManager.cpp index a7f93fb25e..39f83be49f 100644 --- a/ets2panda/util/importPathManager.cpp +++ b/ets2panda/util/importPathManager.cpp @@ -28,9 +28,11 @@ #include "compiler/lowering/ets/declGenPhase.h" #include "libarkfile/class_data_accessor-inl.h" -#include "libarkfile/file-inl.h" #include "libpandabase/utils/logger.h" #include +#include +#include +#include #ifdef USE_UNIX_SYSCALL #include @@ -45,6 +47,12 @@ namespace fs = std::filesystem; namespace fs = std::experimental::filesystem; #endif #endif + +#ifdef _WIN32 +#include +#else +#include +#endif namespace ark::es2panda::util { constexpr size_t SUPPORTED_INDEX_FILES_SIZE = 4; @@ -65,6 +73,43 @@ static bool IsAbsolute(const std::string &path) #endif // ARKTSCONFIG_USE_FILESYSTEM } +std::string DeleteEscapeSymbols(const std::string &input) { + std::string output; + output.reserve(input.size()); + + for (size_t i = 0; i < input.size(); ++i) { + if (input[i] == '\\' && i + 1 < input.size()) { + switch (input[i + 1]) { + case 'n': + output.push_back('\n'); + ++i; + break; + case '?': + output.push_back('?'); + ++i; + break; + case '\'': { + std::string_view pattern = "\\'use static\\'"; + if (input.compare(i, pattern.size(), pattern) == 0) { + output += "'use static'"; + i += pattern.size() - 1; + } else { + output.push_back('\''); + } + break; + } + default: + output.push_back(input[i]); + break; + } + } else { + output.push_back(input[i]); + } + } + + return output; +} + void RemoveEscapedNewlines(std::string &s) { std::string pattern = "\\n"; @@ -74,33 +119,66 @@ void RemoveEscapedNewlines(std::string &s) } } -void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) +std::string ImportPathManager::ExtractModuleName(const panda_file::File &pf, const panda_file::File::EntityId &classId) { - ES2PANDA_ASSERT(!IsAbsolute(std::string(importData.resolvedSource))); + // processing name to get ohmUrl + std::string name = utf::Mutf8AsCString(pf.GetStringData(classId).data); + auto type = pandasm::Type::FromDescriptor(name); + type = pandasm::Type(type.GetNameWithoutRank(), type.GetRank()); + auto recordName = type.GetPandasmName(); + + // rely on the following mangling: .ETSGLOBAL + auto etsGlobalSuffix = std::string(".") + std::string(compiler::Signatures::ETS_GLOBAL); + ES2PANDA_ASSERT(Helpers::EndsWith(recordName, etsGlobalSuffix)); + return recordName.substr(0, recordName.size() - etsGlobalSuffix.size()); // moduleName +} + +std::chrono::system_clock::time_point getFileCreationTime(const std::string &filePath) +{ +#ifdef _WIN32 + HANDLE hFile = CreateFileW(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + LOG(FATAL, ES2PANDA) << "Failed to load a provided file: " << filePath << std::endl; + } + + FILETIME creationTime, accessTime, writeTime; + if (!GetFileTime(hFile, &creationTime, &accessTime, &writeTime)) { + CloseHandle(hFile); + LOG(FATAL, ES2PANDA) << "Failed to get the file creation time" << filePath << std::endl; + } + CloseHandle(hFile); + + ULARGE_INTEGER ull; + ull.LowPart = creationTime.dwLowDateTime; + ull.HighPart = creationTime.dwHighDateTime; + + return std::chrono::system_clock::time_point( + std::chrono::duration_cast(std::chrono::nanoseconds(ull.QuadPart * 100))); +#else + auto ftime = fs::last_write_time(filePath); + auto sctp = std::chrono::time_point_cast( + ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now()); + return sctp; +#endif +} + +void ImportPathManager::ProcessExternalLibraryImportSimple(ImportMetadata &importData) +{ + // take the classes that contain ModuleDeclaration annotation only + // note(lirismankarina): remove this part when the reading from several abc will be fully handled auto it = arktsConfig_->Dependencies().find(std::string(importData.resolvedSource)); ES2PANDA_ASSERT(it != arktsConfig_->Dependencies().cend()); const auto &externalModuleImportData = it->second; - importData.lang = externalModuleImportData.GetLanguage().GetId(); - importData.declPath = externalModuleImportData.Path(); - // process .d.ets "path" in "dependencies" - // process empty "path" in dependencies, since in interop we allow imports without typecheck - if (!Helpers::EndsWith(externalModuleImportData.Path(), ".abc")) { - importData.importFlags |= ImportFlags::EXTERNAL_SOURCE_IMPORT; - importData.ohmUrl = externalModuleImportData.OhmUrl(); - return; - } - - // process .abc "path" in "dependencies" - ES2PANDA_ASSERT(Helpers::EndsWith(std::string(externalModuleImportData.Path()), ".abc")); importData.importFlags |= ImportFlags::EXTERNAL_BINARY_IMPORT; - // NOTE(itrubachev): support binary file after ark_link #26280 + auto pf = panda_file::OpenPandaFile(std::string {externalModuleImportData.Path()}); if (!pf) { LOG(FATAL, ES2PANDA) << "Failed to load a provided abc file: " << externalModuleImportData.Path(); } - // take the classes that contain ModuleDeclaration annotation onlyy + ES2PANDA_ASSERT(pf->GetExported().size() == 1); + for (auto id : pf->GetExported()) { panda_file::File::EntityId classId(id); panda_file::ClassDataAccessor cda(*pf, classId); @@ -113,7 +191,7 @@ void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) auto value = elem.GetScalarValue(); const auto idAnno = value.Get(); std::stringstream ss; - ss << StringDataToString(pf->GetStringData(idAnno)); + ss << panda_file::StringDataToString(pf->GetStringData(idAnno)); std::string declText = ss.str(); if (!declText.empty()) { RemoveEscapedNewlines(declText); @@ -126,16 +204,122 @@ void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) return; } // processing name to get ohmUrl - std::string name = utf::Mutf8AsCString(pf->GetStringData(classId).data); - auto type = pandasm::Type::FromDescriptor(name); - type = pandasm::Type(type.GetNameWithoutRank(), type.GetRank()); - auto recordName = type.GetPandasmName(); + importData.ohmUrl = util::UString(ExtractModuleName(*pf, classId), allocator_).View().Utf8(); + } +} + +void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) +{ + auto resSource = std::string(importData.resolvedSource); + ES2PANDA_ASSERT(!IsAbsolute(resSource)); + auto it = arktsConfig_->Dependencies().find(resSource); + ES2PANDA_ASSERT(it != arktsConfig_->Dependencies().cend()); + const auto &externalModuleImportData = it->second; + importData.lang = externalModuleImportData.GetLanguage().GetId(); + importData.declPath = externalModuleImportData.Path(); + + const std::string dEtsSuffix = ".d.ets"; + const std::string abcSuffix = ".abc"; + const std::string etsstdlibAbcSuffix = "etsstdlib.abc"; + const std::string etsstdlibPathPart = "/etsstdlib/"; // currently does not work is the dir does not exist + + // process .d.ets "path" in "dependencies" + // process empty "path" in dependencies, since in interop we allow imports without typecheck + if (!Helpers::EndsWith(std::string(externalModuleImportData.Path()), abcSuffix)) { + importData.importFlags |= ImportFlags::EXTERNAL_SOURCE_IMPORT; + importData.ohmUrl = externalModuleImportData.OhmUrl(); + return; + } - // rely on the following mangling: .ETSGLOBAL - auto etsGlobalSuffix = std::string(".") + std::string(compiler::Signatures::ETS_GLOBAL); - ES2PANDA_ASSERT(Helpers::EndsWith(recordName, etsGlobalSuffix)); - auto moduleName = recordName.substr(0, recordName.size() - etsGlobalSuffix.size()); - importData.ohmUrl = util::UString(moduleName, allocator_).View().Utf8(); + if (arktsConfig_->CacheDir().empty()) { + std::cout << arktsConfig_->ConfigPath() << std::endl; + LOG(FATAL, ES2PANDA) << "No cache dir provided for arktsconfig: " + << util::StringView(arktsConfig_->ConfigPath()); + return; // Note (lirismankarina): what to do? error? take from other place? + } + + // process .abc "path" in "dependencies" + ES2PANDA_ASSERT(Helpers::EndsWith(std::string(externalModuleImportData.Path()), abcSuffix)); + + // Note(lirismankarina): current realization is related on cacheDir (non-empty path) + // check is the related d.ets already exists in disk cache + if (!Helpers::EndsWith(std::string(externalModuleImportData.Path()), etsstdlibAbcSuffix)) { + // currently only two modes are supported: + // 1. import from .abc file with one package (simple case) + // 2. import from etstdlib.abc + // so, for this case, if it is not etsstdlib.abc -> handle simple case + return ProcessExternalLibraryImportSimple(importData); + } + + std::replace(resSource.begin(), resSource.end(), '/', '.'); + auto fileNameToCheck = arktsConfig_->CacheDir() + etsstdlibPathPart + resSource + dEtsSuffix; + if (fs::exists(fileNameToCheck) && fs::is_regular_file(fileNameToCheck)) { + bool cachedFileIsOlderThanLib = + getFileCreationTime(fileNameToCheck) < getFileCreationTime(std::string(externalModuleImportData.Path())); + if (!cachedFileIsOlderThanLib) { + importData.declPath = util::UString(fileNameToCheck, allocator_).View().Utf8(); + importData.importFlags |= ImportFlags::EXTERNAL_SOURCE_IMPORT; + importData.ohmUrl = + resSource; // Note(lirismankarina): check if we need clear module name creating here in case of stdlib + return; + } + } + + importData.importFlags |= ImportFlags::EXTERNAL_BINARY_IMPORT; + // NOTE(itrubachev): support binary file after ark_link #26280 + + auto pf = panda_file::OpenPandaFile(std::string {externalModuleImportData.Path()}); + if (!pf) { + LOG(FATAL, ES2PANDA) << "Failed to load a provided abc file: " << externalModuleImportData.Path(); + } + + if (pf->GetExported().size() > 1) { // need to split for several d.ets. Currently works only for etsstdlib.abc + + for (auto id : pf->GetExported()) { + panda_file::File::EntityId classId(id); + panda_file::ClassDataAccessor cda(*pf, classId); + auto moduleName = ExtractModuleName(*pf, classId); + importData.ohmUrl = util::UString(moduleName, allocator_).View().Utf8(); + + // create a name for d.ets file - related on module name and cache dir + auto declFileName = arktsConfig_->CacheDir() + etsstdlibPathPart + moduleName + dEtsSuffix; + + // the module name`s separators are '.' now, but for resolvedSource we have '/' + std::replace(moduleName.begin(), moduleName.end(), '.', '/'); + if (importData.resolvedSource == moduleName) { + // changing path from etsstdlib.abc for related d.ets - ex. etsstdlib.abc -> std.core.d.ets + importData.declPath = util::UString(declFileName, allocator_).View().Utf8(); + } else { + // if the current resolvedSource is not the same as current class, just go to the next class + continue; + } + + std::stringstream ss; + // a class can contain more than one ModuleAnnotation annotations, + // so need to search in all of them in order to take all the declarations + cda.EnumerateAnnotations([&pf, &ss](panda_file::File::EntityId ann_id) { + panda_file::AnnotationDataAccessor annotationAccessor(*pf, ann_id); + auto annName = + std::string(ark::utf::Mutf8AsCString(pf->GetStringData(annotationAccessor.GetClassId()).data)); + if (annName == ANNOTATION_MODULE_DECLARATION.data()) { + auto elem = annotationAccessor.GetElement(0); + auto value = elem.GetScalarValue(); + const auto idAnno = value.Get(); + // collecting the string values of annotations + ss << panda_file::StringDataToString(pf->GetStringData(idAnno)); + } + return true; + }); + if (ss.str().size() > 0) { + std::ofstream declFile(declFileName); + declFile << DeleteEscapeSymbols(ss.str()); + // changing the flags for import - the analysis will continue as if the original file was a .d.ets + importData.importFlags &= ~ImportFlags::EXTERNAL_BINARY_IMPORT; + importData.importFlags |= ImportFlags::EXTERNAL_SOURCE_IMPORT; + } + return; // if we reach this line, we already took that one class and created that one d.ets, no need to + // continue + } } } @@ -180,6 +364,7 @@ ImportPathManager::ImportMetadata ImportPathManager::GatherImportMetadata(parser isDynamic_ = program->IsDeclForDynamicStaticInterop(); auto curModulePath = isDynamic_ ? program->ModuleInfo().moduleName : program->AbsoluteName(); auto [resolvedImportPath, resolvedIsExternalModule] = ResolvePath(curModulePath.Utf8(), importPath); + if (resolvedImportPath.empty()) { ES2PANDA_ASSERT(diagnosticEngine_.IsAnyError()); return ImportMetadata {util::ImportFlags::NONE, Language::Id::COUNT, ERROR_LITERAL}; diff --git a/ets2panda/util/importPathManager.h b/ets2panda/util/importPathManager.h index 588d91e54d..4d23704de2 100644 --- a/ets2panda/util/importPathManager.h +++ b/ets2panda/util/importPathManager.h @@ -21,6 +21,7 @@ #define USE_UNIX_SYSCALL #endif +#include "libarkfile/file-inl.h" #include "util/arktsconfig.h" #include "util/ustring.h" #include "util/enumbitops.h" @@ -187,6 +188,8 @@ private: std::string TryMatchDependencies(std::string_view fixedPath) const; std::string TryResolvePath(std::string_view fixedPath) const; StringView GetRealPath(StringView path) const; + std::string ExtractModuleName(const panda_file::File &pf, const panda_file::File::EntityId &classId); + void ProcessExternalLibraryImportSimple(ImportMetadata &importData); void ProcessExternalLibraryImport(ImportMetadata &importData); std::string_view TryImportFromDeclarationCache(std::string_view resolvedImportPath) const; -- Gitee From 9e689d7073f33d6b0ce2695e0f418d8c202e5e33 Mon Sep 17 00:00:00 2001 From: lirismankarina Date: Tue, 9 Sep 2025 18:49:57 +0300 Subject: [PATCH 4/5] added mem cache Signed-off-by: lirismankarina --- ets2panda/util/importPathManager.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/ets2panda/util/importPathManager.cpp b/ets2panda/util/importPathManager.cpp index 39f83be49f..b7f2af87bc 100644 --- a/ets2panda/util/importPathManager.cpp +++ b/ets2panda/util/importPathManager.cpp @@ -22,6 +22,7 @@ #include "generated/diagnostic.h" #include "parser/context/parserContext.h" +#include "parser/program/DeclarationCache.h" #include "parser/program/program.h" #include "ir/expressions/literals/stringLiteral.h" @@ -73,7 +74,8 @@ static bool IsAbsolute(const std::string &path) #endif // ARKTSCONFIG_USE_FILESYSTEM } -std::string DeleteEscapeSymbols(const std::string &input) { +std::string DeleteEscapeSymbols(const std::string &input) +{ std::string output; output.reserve(input.size()); @@ -253,14 +255,28 @@ void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) std::replace(resSource.begin(), resSource.end(), '/', '.'); auto fileNameToCheck = arktsConfig_->CacheDir() + etsstdlibPathPart + resSource + dEtsSuffix; + + // memory cache checking + static auto &declarationCache = parser::DeclarationCache::Instance(); + auto declaration = declarationCache.GetDeclaration(fileNameToCheck); + if (declaration != parser::DeclarationCache::ABSENT) { + return; + } + + // since was not found in memory cache, take from disk cache if (fs::exists(fileNameToCheck) && fs::is_regular_file(fileNameToCheck)) { bool cachedFileIsOlderThanLib = - getFileCreationTime(fileNameToCheck) < getFileCreationTime(std::string(externalModuleImportData.Path())); + getFileCreationTime(fileNameToCheck) < getFileCreationTime(std::string(externalModuleImportData.Path())); if (!cachedFileIsOlderThanLib) { importData.declPath = util::UString(fileNameToCheck, allocator_).View().Utf8(); importData.importFlags |= ImportFlags::EXTERNAL_SOURCE_IMPORT; - importData.ohmUrl = - resSource; // Note(lirismankarina): check if we need clear module name creating here in case of stdlib + importData.ohmUrl = resSource; + + // put in memory cache + std::ifstream declFile(fileNameToCheck); + std::stringstream ss {}; + ss << declFile.rdbuf(); + declaration = declarationCache.AddDeclaration(fileNameToCheck, std::make_shared(ss.str())); return; } } -- Gitee From 8c7366dd2a16749bf2ddc8dd24bd8d7a2a1e7b1a Mon Sep 17 00:00:00 2001 From: lirismankarina Date: Tue, 9 Sep 2025 19:56:44 +0300 Subject: [PATCH 5/5] minor fixes --- ets2panda/CMakeLists.txt | 29 +++++----- ets2panda/ir/srcDump.h | 2 +- ets2panda/util/importPathManager.cpp | 86 +++++++++++++++------------- ets2panda/util/importPathManager.h | 5 ++ 4 files changed, 69 insertions(+), 53 deletions(-) diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 7768e37106..367458c01a 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -53,6 +53,8 @@ else() set(DEFAULT_ARKTSCONFIG "${CMAKE_BINARY_DIR}/bin") endif() file(MAKE_DIRECTORY "${GENERATED_DIR}") +set(DEFAULT_CACHE_DIR "${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib") +file(MAKE_DIRECTORY "${DEFAULT_CACHE_DIR}") if(PANDA_WITH_ETS) file(WRITE "${GENERATED_DIR}/arktsconfig.json" "{\n" @@ -61,6 +63,7 @@ if(PANDA_WITH_ETS) " \"compilerOptions\": {\n" " \"baseUrl\": \"${PANDA_ROOT}\",\n" + " \"cacheDir\": \"${DEFAULT_CACHE_DIR}\",\n" " \"paths\": {\n" " \"@ohos.buffer\": [\"${STATIC_CORE}${DELIM}plugins${DELIM}ets${DELIM}sdk${DELIM}api${DELIM}@ohos.buffer.ets\"],\n" " \"@ohos.util.ArrayList\": [\"${STATIC_CORE}${DELIM}plugins${DELIM}ets${DELIM}sdk${DELIM}api${DELIM}@ohos.util.ArrayList.ets\"],\n" @@ -87,19 +90,19 @@ if(PANDA_WITH_ETS) " \"import_tests\": [\"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/import_tests\"]\n" " },\n" " \"dependencies\": {\n" - " \"std/core\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.core.d.ets\" },\n" - " \"std/math\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.math.d.ets\" },\n" - " \"std/math/consts\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.math.consts.d.ets\" },\n" - " \"std/containers\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.containers.d.ets\" },\n" - " \"std/interop/js\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.interop.js.d.ets\" },\n" - " \"std/time\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.time.d.ets\" },\n" - " \"std/debug\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.debug.d.ets\" },\n" - " \"std/debug/concurrency\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.debug.concurrency.d.ets\" },\n" - " \"std/testing\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.testing.d.ets\" },\n" - " \"std/concurrency\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.concurrency.d.ets\" },\n" - " \"std/annotations\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.annotations.d.ets\" },\n" - " \"std/interop\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}std.interop.d.ets\" },\n" - " \"escompat\": { \"path\": \"${PANDA_BINARY_ROOT}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib${DELIM}escompat.d.ets\" },\n" + " \"std/core\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/math\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/math/consts\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/containers\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/interop/js\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/time\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/debug\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/debug/concurrency\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/testing\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/concurrency\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/annotations\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"std/interop\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" + " \"escompat\": { \"path\": \"${CMAKE_BINARY_DIR}${DELIM}plugins${DELIM}ets${DELIM}etsstdlib.abc\" },\n" " \"dynamic_import_tests\": {\"language\": \"js\", \"ohmUrl\": \"dynamic_import_tests\"},\n" " \"dynamic_import_tests/modules/instanceof\": {\"language\": \"js\", \"path\": \"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/dynamic_import_tests/modules/instanceof.ets\", \"ohmUrl\": \"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/dynamic_import_tests/modules/instanceof.ets\"},\n" " \"dynamic_import_tests/modules/module\": {\"language\": \"js\", \"path\": \"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/dynamic_import_tests/modules/module.ets\", \"ohmUrl\": \"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/dynamic_import_tests/modules/module.ets\"}\n" diff --git a/ets2panda/ir/srcDump.h b/ets2panda/ir/srcDump.h index 5d86edfd32..ddbdf34f1d 100644 --- a/ets2panda/ir/srcDump.h +++ b/ets2panda/ir/srcDump.h @@ -163,7 +163,7 @@ private: std::queue> taskQueue_ {}; // a dictionary with "hidden" nodes that may be dumped at post-dump. // NOTE(dkofanov): it should be aware of names collision, 'string' is to be changed to 'Variable *'. - std::unordered_map unExportNode_ {}; + std::map unExportNode_ {}; }; class SrcDumper { diff --git a/ets2panda/util/importPathManager.cpp b/ets2panda/util/importPathManager.cpp index b7f2af87bc..8641faf27b 100644 --- a/ets2panda/util/importPathManager.cpp +++ b/ets2panda/util/importPathManager.cpp @@ -164,14 +164,54 @@ std::chrono::system_clock::time_point getFileCreationTime(const std::string &fil #endif } +bool ImportPathManager::DeclarationIsInCache(ImportMetadata &importData) +{ + auto resSource = std::string(importData.resolvedSource); + auto it = arktsConfig_->Dependencies().find(std::string(importData.resolvedSource)); + ES2PANDA_ASSERT(it != arktsConfig_->Dependencies().cend()); + const auto &externalModuleImportData = it->second; + + std::replace(resSource.begin(), resSource.end(), '/', '.'); + auto fileNameToCheck = arktsConfig_->CacheDir() + "/" + resSource + dEtsSuffix.data(); + + // memory cache checking + static auto &declarationCache = parser::DeclarationCache::Instance(); + auto declaration = declarationCache.GetDeclaration(fileNameToCheck); + if (declaration != parser::DeclarationCache::ABSENT) { + return true; + } + + // since was not found in memory cache, take from disk cache + if (fs::exists(fileNameToCheck) && fs::is_regular_file(fileNameToCheck)) { + bool cachedFileIsOlderThanLib = + getFileCreationTime(fileNameToCheck) < getFileCreationTime(std::string(externalModuleImportData.Path())); + if (!cachedFileIsOlderThanLib) { + importData.declPath = util::UString(fileNameToCheck, allocator_).View().Utf8(); + importData.importFlags |= ImportFlags::EXTERNAL_SOURCE_IMPORT; + importData.ohmUrl = resSource; + + // put in memory cache + std::ifstream declFile(fileNameToCheck); + std::stringstream ss {}; + ss << declFile.rdbuf(); + declaration = declarationCache.AddDeclaration(std::move(fileNameToCheck), std::make_shared(ss.str())); + return true; + } + } + return false; +} + void ImportPathManager::ProcessExternalLibraryImportSimple(ImportMetadata &importData) { // take the classes that contain ModuleDeclaration annotation only - // note(lirismankarina): remove this part when the reading from several abc will be fully handled auto it = arktsConfig_->Dependencies().find(std::string(importData.resolvedSource)); ES2PANDA_ASSERT(it != arktsConfig_->Dependencies().cend()); const auto &externalModuleImportData = it->second; + if (DeclarationIsInCache(importData)) { + return; + } + importData.importFlags |= ImportFlags::EXTERNAL_BINARY_IMPORT; auto pf = panda_file::OpenPandaFile(std::string {externalModuleImportData.Path()}); @@ -220,11 +260,6 @@ void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) importData.lang = externalModuleImportData.GetLanguage().GetId(); importData.declPath = externalModuleImportData.Path(); - const std::string dEtsSuffix = ".d.ets"; - const std::string abcSuffix = ".abc"; - const std::string etsstdlibAbcSuffix = "etsstdlib.abc"; - const std::string etsstdlibPathPart = "/etsstdlib/"; // currently does not work is the dir does not exist - // process .d.ets "path" in "dependencies" // process empty "path" in dependencies, since in interop we allow imports without typecheck if (!Helpers::EndsWith(std::string(externalModuleImportData.Path()), abcSuffix)) { @@ -243,8 +278,6 @@ void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) // process .abc "path" in "dependencies" ES2PANDA_ASSERT(Helpers::EndsWith(std::string(externalModuleImportData.Path()), abcSuffix)); - // Note(lirismankarina): current realization is related on cacheDir (non-empty path) - // check is the related d.ets already exists in disk cache if (!Helpers::EndsWith(std::string(externalModuleImportData.Path()), etsstdlibAbcSuffix)) { // currently only two modes are supported: // 1. import from .abc file with one package (simple case) @@ -253,34 +286,11 @@ void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) return ProcessExternalLibraryImportSimple(importData); } - std::replace(resSource.begin(), resSource.end(), '/', '.'); - auto fileNameToCheck = arktsConfig_->CacheDir() + etsstdlibPathPart + resSource + dEtsSuffix; - - // memory cache checking - static auto &declarationCache = parser::DeclarationCache::Instance(); - auto declaration = declarationCache.GetDeclaration(fileNameToCheck); - if (declaration != parser::DeclarationCache::ABSENT) { + // trying to find declaration in memory and disk caches + if (DeclarationIsInCache(importData)) { return; } - // since was not found in memory cache, take from disk cache - if (fs::exists(fileNameToCheck) && fs::is_regular_file(fileNameToCheck)) { - bool cachedFileIsOlderThanLib = - getFileCreationTime(fileNameToCheck) < getFileCreationTime(std::string(externalModuleImportData.Path())); - if (!cachedFileIsOlderThanLib) { - importData.declPath = util::UString(fileNameToCheck, allocator_).View().Utf8(); - importData.importFlags |= ImportFlags::EXTERNAL_SOURCE_IMPORT; - importData.ohmUrl = resSource; - - // put in memory cache - std::ifstream declFile(fileNameToCheck); - std::stringstream ss {}; - ss << declFile.rdbuf(); - declaration = declarationCache.AddDeclaration(fileNameToCheck, std::make_shared(ss.str())); - return; - } - } - importData.importFlags |= ImportFlags::EXTERNAL_BINARY_IMPORT; // NOTE(itrubachev): support binary file after ark_link #26280 @@ -298,7 +308,7 @@ void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) importData.ohmUrl = util::UString(moduleName, allocator_).View().Utf8(); // create a name for d.ets file - related on module name and cache dir - auto declFileName = arktsConfig_->CacheDir() + etsstdlibPathPart + moduleName + dEtsSuffix; + auto declFileName = arktsConfig_->CacheDir() + "/" + moduleName + dEtsSuffix.data(); // the module name`s separators are '.' now, but for resolvedSource we have '/' std::replace(moduleName.begin(), moduleName.end(), '.', '/'); @@ -311,8 +321,8 @@ void ImportPathManager::ProcessExternalLibraryImport(ImportMetadata &importData) } std::stringstream ss; - // a class can contain more than one ModuleAnnotation annotations, - // so need to search in all of them in order to take all the declarations + // a class can contain more than one ModuleAnnotation annotation, + // so we need to search in all of them in order to take all the declarations cda.EnumerateAnnotations([&pf, &ss](panda_file::File::EntityId ann_id) { panda_file::AnnotationDataAccessor annotationAccessor(*pf, ann_id); auto annName = @@ -347,8 +357,6 @@ std::string_view ImportPathManager::TryImportFromDeclarationCache(std::string_vi !ark::os::file::File::IsRegularFile(std::string(resolvedImportPath))) { return resolvedImportPath; } - const std::string etsSuffix = ".ets"; - const std::string dEtsSuffix = ".d.ets"; const auto &rootDir = ArkTSConfig().get()->RootDir(); const auto &cacheDir = ArkTSConfig().get()->CacheDir(); if (cacheDir.empty() || rootDir.empty()) { @@ -361,7 +369,7 @@ std::string_view ImportPathManager::TryImportFromDeclarationCache(std::string_vi const auto &relativeFilePath = resolvedImportPath.substr(rootDir.size(), resolvedImportPath.size() - rootDir.size()); const auto &declarationCacheFile = - cacheDir + std::string(relativeFilePath.substr(0, relativeFilePath.size() - etsSuffix.size())) + dEtsSuffix; + cacheDir + std::string(relativeFilePath.substr(0, relativeFilePath.size() - etsSuffix.size())) + dEtsSuffix.data(); if (!ark::os::file::File::IsRegularFile(declarationCacheFile)) { return resolvedImportPath; diff --git a/ets2panda/util/importPathManager.h b/ets2panda/util/importPathManager.h index 4d23704de2..8bb428eaa1 100644 --- a/ets2panda/util/importPathManager.h +++ b/ets2panda/util/importPathManager.h @@ -80,6 +80,10 @@ public: static constexpr auto DUMMY_PATH = "dummy_path"; // CC-OFF(G.NAM.03-CPP) project code style static constexpr std::string_view ANNOTATION_MODULE_DECLARATION = "Lstd/annotations/ModuleDeclaration;"; // CC-OFF(G.NAM.03-CPP) project code style + static constexpr std::string_view etsSuffix = ".ets"; + static constexpr std::string_view dEtsSuffix = ".d.ets"; + static constexpr std::string_view abcSuffix = ".abc"; + static constexpr std::string_view etsstdlibAbcSuffix = "etsstdlib.abc"; struct ImportMetadata { // NOLINTBEGIN(misc-non-private-member-variables-in-classes) ImportFlags importFlags {}; @@ -188,6 +192,7 @@ private: std::string TryMatchDependencies(std::string_view fixedPath) const; std::string TryResolvePath(std::string_view fixedPath) const; StringView GetRealPath(StringView path) const; + bool DeclarationIsInCache(ImportMetadata &importData); std::string ExtractModuleName(const panda_file::File &pf, const panda_file::File::EntityId &classId); void ProcessExternalLibraryImportSimple(ImportMetadata &importData); void ProcessExternalLibraryImport(ImportMetadata &importData); -- Gitee