From f462bf5e2537ed99cc3dfe7cb803a228d14ec7d4 Mon Sep 17 00:00:00 2001 From: Ilya Trubachev Date: Wed, 30 Apr 2025 00:01:21 +0800 Subject: [PATCH] Support import from .abc file Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/IC7O5K Signed-off-by: Ilya Trubachev --- ets2panda/BUILD.gn | 13 +- ets2panda/CMakeLists.txt | 9 +- ets2panda/aot/BUILD.gn | 2 + .../bindings/src/build/generateArkTSConfig.ts | 34 ++-- ets2panda/compiler/core/ETSemitter.cpp | 49 ----- ets2panda/compiler/core/compilerImpl.cpp | 10 - .../compiler/lowering/ets/declGenPhase.cpp | 67 +++++++ .../compiler/lowering/ets/declGenPhase.h | 48 +++++ ets2panda/compiler/lowering/phase.cpp | 5 +- ets2panda/docs/cheatsheet.md | 2 +- ets2panda/docs/import_export.md | 2 +- .../src/build/generate_arktsconfig.ts | 48 ++--- ets2panda/evaluate/entityDeclarator.cpp | 2 +- ets2panda/ir/ets/etsImportDeclaration.h | 4 +- ets2panda/parser/ETSparser.cpp | 14 +- ets2panda/parser/program/program.h | 13 -- .../check-decl-path/arktsconfig.in.decl.json | 4 +- .../arktsconfig.in.decl.json | 4 +- .../arktsconfig.in.decl.json | 4 +- .../arktsconfig.in.decl.json | 4 +- .../typecheck-decl/arktsconfig.in.decl.json | 4 +- .../arktsconfig_include.cpp | 3 +- .../test/unit/dynamic/dynamic_call_test.cpp | 2 +- .../get_compiler_options_diagnostics_test.cpp | 11 +- ets2panda/test/unit/plugin/CMakeLists.txt | 10 +- .../use_plugin_to_test_export_table.cpp | 163 ---------------- ets2panda/util/arktsconfig.cpp | 184 +++++++----------- ets2panda/util/arktsconfig.h | 60 ++---- .../util/diagnostic/arktsconfig_error.yaml | 10 +- ets2panda/util/diagnostic/warning.yaml | 4 - ets2panda/util/importPathManager.cpp | 120 +++++++----- ets2panda/util/importPathManager.h | 24 ++- ets2panda/util/language.h | 11 ++ ets2panda/util/options.cpp | 5 +- ets2panda/util/options.yaml | 10 +- 35 files changed, 403 insertions(+), 556 deletions(-) create mode 100644 ets2panda/compiler/lowering/ets/declGenPhase.cpp create mode 100644 ets2panda/compiler/lowering/ets/declGenPhase.h delete mode 100644 ets2panda/test/unit/plugin/use_plugin_to_test_export_table.cpp diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 5a788f0982..a6883d4d3e 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -214,6 +214,7 @@ libes2panda_sources = [ "compiler/lowering/ets/constantExpressionLowering.cpp", "compiler/lowering/ets/convertPrimitiveCastMethodCall.cpp", "compiler/lowering/ets/declareOverloadLowering.cpp", + "compiler/lowering/ets/declGenPhase.cpp", "compiler/lowering/ets/defaultParametersInConstructorLowering.cpp", "compiler/lowering/ets/defaultParametersLowering.cpp", "compiler/lowering/ets/enumLowering.cpp", @@ -1124,6 +1125,7 @@ libes2panda_configs = [ ":libes2panda_config", "$ark_root/libpandabase:arkbase_public_config", "$ark_root/libpandafile:arkfile_public_config", + "$ark_root/abc2program:arkts_abc2program_public_config", ] libes2panda_public_configs = [ @@ -1173,6 +1175,7 @@ ohos_source_set("libes2panda_frontend_static") { "runtime_core:libarktsbase_package", "runtime_core:libarktscompiler_package", "runtime_core:libarktsfile_package", + "runtime_core:libarktsabc2program_package", sdk_libc_secshared_dep, ] part_name = "ets_frontend" @@ -1213,7 +1216,14 @@ ohos_source_set("libes2panda_public_frontend_static") { deps = [ ":libes2panda_frontend_static" ] if (ark_standalone_build || ark_static_standalone_build) { - deps += [ "$ark_root/bytecode_optimizer:libarktsbytecodeopt_package" ] + deps += [ + "$ark_root/bytecode_optimizer:libarktsbytecodeopt_package", + "$ark_root/abc2program:libarktsabc2program_package", + "$ark_root/assembler:libarktsassembler", + "$ark_root/compiler:libarktscompiler", + "$ark_root/libpandabase:libarktsbase", + "$ark_root/libpandafile:libarktsfile", + ] } if (target_os != "win" && target_os != "mingw" && target_os != "winuwp") { @@ -1223,6 +1233,7 @@ ohos_source_set("libes2panda_public_frontend_static") { external_deps = [ "runtime_core:libarktsbytecodeopt_package", + "runtime_core:libarktsabc2program_package", sdk_libc_secshared_dep, ] part_name = "ets_frontend" diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 2143314080..a6b0cb1894 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -73,10 +73,10 @@ if(PANDA_WITH_ETS) " \"@arkts.collections\": [\"${STATIC_CORE}${DELIM}plugins${DELIM}ets${DELIM}sdk${DELIM}arkts${DELIM}@arkts.collections.ets\"],\n" " \"import_tests\": [\"${CMAKE_CURRENT_SOURCE_DIR}/test/parser/ets/import_tests\"]\n" " },\n" - " \"dynamicPaths\": {\n" + " \"dependencies\": {\n" " \"dynamic_import_tests\": {\"language\": \"js\", \"ohmUrl\": \"dynamic_import_tests\"},\n" - " \"dynamic_import_tests/modules/instanceof\": {\"language\": \"js\", \"declPath\": \"${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\", \"declPath\": \"${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" + " \"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" " }\n" " }\n" "}\n" @@ -283,6 +283,7 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/constantExpressionLowering.cpp compiler/lowering/ets/convertPrimitiveCastMethodCall.cpp compiler/lowering/ets/declareOverloadLowering.cpp + compiler/lowering/ets/declGenPhase.cpp compiler/lowering/ets/defaultParametersInConstructorLowering.cpp compiler/lowering/ets/defaultParametersLowering.cpp compiler/lowering/ets/exportAnonymousConst.cpp @@ -692,7 +693,7 @@ endif() panda_target_link_libraries(es2panda-lib PUBLIC arkbase hmicuuc.z - PRIVATE arkassembler arkdisassembler arkfile + PRIVATE arkassembler arkdisassembler arkfile abc2program ) 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 2a76c53b3d..7efccf6585 100644 --- a/ets2panda/aot/BUILD.gn +++ b/ets2panda/aot/BUILD.gn @@ -36,6 +36,7 @@ ohos_executable("ets2panda") { "$ark_root/bytecode_optimizer:bytecodeopt_public_config", "$ark_root/compiler:arkcompiler_public_config", "$ark_root/runtime:arkruntime_public_config", + "$ark_root/abc2program:arkts_abc2program_public_config", ] deps = [ @@ -57,6 +58,7 @@ 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/src/build/generateArkTSConfig.ts b/ets2panda/bindings/src/build/generateArkTSConfig.ts index fe1dc108fc..2197374fdf 100644 --- a/ets2panda/bindings/src/build/generateArkTSConfig.ts +++ b/ets2panda/bindings/src/build/generateArkTSConfig.ts @@ -20,10 +20,10 @@ import { changeFileExtension, ensurePathExists } from '../utils'; import { BuildConfig, ModuleInfo } from '../types'; import { LANGUAGE_VERSION, SYSTEM_SDK_PATH_FROM_SDK } from '../preDefine'; -interface DynamicPathItem { +interface DependencyItem { language: string; - declPath: string; - runtimeName: string; + path: string; + ohmUrl: string; } interface ArkTSConfigObject { @@ -31,9 +31,8 @@ interface ArkTSConfigObject { package: string; baseUrl: string; paths: Record; - dependencies: string[] | undefined; entry: string; - dynamicPaths: Record; + dependencies: Record; }; } @@ -128,20 +127,13 @@ export class ArkTSConfigGenerator { return this.pathSection; } - private getDependenciesSection(moduleInfo: ModuleInfo, dependenciesSection: string[]): void { - let depModules: Map = moduleInfo.staticDepModuleInfos; - depModules.forEach((depModuleInfo: ModuleInfo) => { - dependenciesSection.push(depModuleInfo.arktsConfigFile); - }); - } - private getOhmurl(file: string, moduleInfo: ModuleInfo): string { let unixFilePath: string = file.replace(/\\/g, '/'); let ohmurl: string = moduleInfo.packageName + '/' + unixFilePath; return changeFileExtension(ohmurl, ''); } - private getDynamicPathSection(moduleInfo: ModuleInfo, dynamicPathSection: Record): void { + private getDependenciesSection(moduleInfo: ModuleInfo, dependencySection: Record): void { let depModules: Map = moduleInfo.dynamicDepModuleInfos; depModules.forEach((depModuleInfo: ModuleInfo) => { @@ -153,16 +145,16 @@ export class ArkTSConfigGenerator { let declFilesObject = JSON.parse(fs.readFileSync(depModuleInfo.declFilesPath, 'utf-8')); Object.keys(declFilesObject.files).forEach((file: string) => { let ohmurl: string = this.getOhmurl(file, depModuleInfo); - dynamicPathSection[ohmurl] = { + dependencySection[ohmurl] = { language: 'js', - declPath: declFilesObject.files[file].declPath, - runtimeName: declFilesObject.files[file].ohmUrl + path: declFilesObject.files[file].declPath, + ohmUrl: declFilesObject.files[file].ohmUrl }; let absFilePath: string = path.resolve(depModuleInfo.moduleRootPath, file); let entryFileWithoutExtension: string = changeFileExtension(depModuleInfo.entryFile, ''); if (absFilePath === entryFileWithoutExtension) { - dynamicPathSection[depModuleInfo.packageName] = dynamicPathSection[ohmurl]; + dependencySection[depModuleInfo.packageName] = dependencySection[ohmurl]; } }); }); @@ -173,9 +165,8 @@ export class ArkTSConfigGenerator { console.error('SourceRoots not set from hvigor.'); } let pathSection = this.getPathSection(); - let dependenciesSection: string[] = []; - let dynamicPathSection: Record = {}; - this.getDynamicPathSection(moduleInfo, dynamicPathSection); + let dependencySection: Record = {}; + this.getDependenciesSection(moduleInfo, dependencySection); let baseUrl: string = path.resolve(moduleInfo.moduleRootPath, moduleInfo.sourceRoots[0]); let arktsConfig: ArkTSConfigObject = { @@ -183,9 +174,8 @@ export class ArkTSConfigGenerator { package: moduleInfo.packageName, baseUrl: baseUrl, paths: pathSection, - dependencies: dependenciesSection.length === 0 ? undefined : dependenciesSection, entry: moduleInfo.entryFile, - dynamicPaths: dynamicPathSection + dependencies: dependencySection } }; diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index 81ff05cfe2..b0bdd7d66f 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -218,51 +218,6 @@ static std::string GenerateMangledName(const std::string &baseName, const std::s return baseName + "$" + propName; } -static void StoreEntity(std::vector &literals, uint8_t type) -{ - uint32_t emptyValue = 0; - literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE, - static_cast(panda_file::LiteralTag::INTEGER)}); - literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::INTEGER, emptyValue}); - - literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE, - static_cast(panda_file::LiteralTag::ACCESSOR)}); - literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::ACCESSOR, type}); - - literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::TAGVALUE, - static_cast(panda_file::LiteralTag::INTEGER)}); - literals.emplace_back(pandasm::LiteralArray::Literal {panda_file::LiteralTag::INTEGER, emptyValue}); -} - -static std::vector> StoreExportNodes( - std::vector> &declGen, pandasm::Program *program) -{ - std::vector literals; - std::vector> result; - - for (auto &pair : declGen) { - auto declString = std::string {pair.first}; - auto *node = pair.second; - if (node->IsClassProperty() && node->IsConst()) { - StoreEntity(literals, parser::EntityType::CLASS_PROPERTY); - result.emplace_back(declString, node->AsClassProperty()->Id()->Name().Mutf8()); - } else if (node->IsMethodDefinition()) { - StoreEntity(literals, parser::EntityType::METHOD_DEFINITION); - result.emplace_back(declString, node->AsMethodDefinition()->Function()->Scope()->InternalName()); - } else if (node->IsClassDefinition()) { - StoreEntity(literals, parser::EntityType::CLASS_DEFINITION); - result.emplace_back(declString, node->AsClassDefinition()->InternalName().Mutf8()); - } else if (node->IsTSInterfaceDeclaration()) { - StoreEntity(literals, parser::EntityType::TS_INTERFACE_DECLARATION); - result.emplace_back(declString, node->AsTSInterfaceDeclaration()->InternalName().Mutf8()); - } else { - ES2PANDA_UNREACHABLE(); - } - } - program->literalarrayTable.emplace("export_entities", literals); - return result; -} - void ETSEmitter::GenAnnotation() { Program()->lang = EXTENSION; @@ -309,10 +264,6 @@ void ETSEmitter::GenAnnotation() for (auto [arrType, signature] : checker->GlobalArrayTypes()) { GenGlobalArrayRecord(arrType, signature); } - if (Context()->config->options->WasSetWithExportTable()) { - auto result = StoreExportNodes(Context()->parserProgram->DeclGenExportNodes(), Program()); - Program()->exportStrMap = std::move(result); - } } static bool IsFromSelfHeadFile(const std::string &name, const parser::Program *curProg, const parser::Program *extProg) diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 86b978ffe4..61b8a77601 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -175,16 +175,6 @@ static bool RunVerifierAndPhases(public_lib::Context &context, parser::Program & if (afterCheckerPhase && context.diagnosticEngine->IsAnyError()) { return false; } - - if (options.IsGenerateDeclEnabled() && name == compiler::CheckerPhase::NAME) { - std::string path; - if (!options.WasSetGenerateDeclPath()) { - path = ark::os::RemoveExtension(util::BaseName(options.SourceFileName())).append(".d.ets"); - } else { - path = options.GetGenerateDeclPath(); - } - HandleGenerateDecl(program, *context.diagnosticEngine, path); - } } return true; diff --git a/ets2panda/compiler/lowering/ets/declGenPhase.cpp b/ets2panda/compiler/lowering/ets/declGenPhase.cpp new file mode 100644 index 0000000000..1609abacd0 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/declGenPhase.cpp @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "declGenPhase.h" + +#include "checker/ETSchecker.h" +#include "compiler/lowering/util.h" + +namespace ark::es2panda::compiler { + +bool DeclGenPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) +{ + if (!ctx->config->options->IsEmitDeclaration()) { + return true; + } + + checker_ = ctx->GetChecker()->AsETSChecker(); + phaseManager_ = ctx->phaseManager; + + DumpDeclaration(program); + CreateModuleDeclarationAnnotation(program); + + return true; +} + +void DeclGenPhase::DumpDeclaration(parser::Program *program) +{ + declaration_ = program->Ast()->DumpDecl(); + declaration_.erase(0, declaration_.find_first_not_of('\n')); + declaration_.erase(declaration_.find_last_not_of('\n'), declaration_.size() - 1); +} + +void DeclGenPhase::CreateModuleDeclarationAnnotation(parser::Program *program) +{ + auto *const annoUsageIdent = checker_->AllocNode(MODULE_DECLARATION_NAME, checker_->Allocator()); + annoUsageIdent->SetAnnotationUsage(); + + auto flags = ir::ModifierFlags::ANNOTATION_USAGE; + ArenaVector properties(checker_->Allocator()->Adapter()); + auto *singleParamName = + checker_->AllocNode(compiler::Signatures::ANNOTATION_KEY_VALUE, checker_->Allocator()); + auto *declarationLiteral = checker_->AllocNode(declaration_.c_str()); + auto *declarationProp = checker_->AllocNode(singleParamName, declarationLiteral, nullptr, flags, + checker_->Allocator(), false); + properties.push_back(declarationProp); + + auto *annotationUsage = checker_->AllocNode(annoUsageIdent, std::move(properties)); + annotationUsage->AddModifier(flags); + annotationUsage->SetParent(program->GlobalClass()); + + program->GlobalClass()->AddAnnotations(annotationUsage); + Recheck(phaseManager_, checker_->VarBinder()->AsETSBinder(), checker_, annotationUsage); +} + +} // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/declGenPhase.h b/ets2panda/compiler/lowering/ets/declGenPhase.h new file mode 100644 index 0000000000..09534fc7c8 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/declGenPhase.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_LOWERING_DECL_GEN_PHASE_H +#define ES2PANDA_COMPILER_LOWERING_DECL_GEN_PHASE_H + +#include "compiler/lowering/phase.h" + +namespace ark::es2panda::compiler { + +// 1. Generate declaration for checked AST +// 2. Store declaration to annotation to ETSGLOBAL class +class DeclGenPhase : public PhaseForBodies { +public: + std::string_view Name() const override + { + return "DeclGenPhase"; + } + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; + + static constexpr std::string_view const MODULE_DECLARATION_NAME {"ModuleDeclaration"}; + static constexpr std::string_view const MODULE_DECLARATION_ANNOTATION {"std.annotations.ModuleDeclaration"}; + +private: + void DumpDeclaration(parser::Program *program); + void CreateModuleDeclarationAnnotation(parser::Program *program); + + checker::ETSChecker *checker_ {nullptr}; + compiler::PhaseManager *phaseManager_ {nullptr}; + std::string declaration_; +}; + +} // namespace ark::es2panda::compiler + +#endif // ES2PANDA_COMPILER_LOWERING_DECL_GEN_PHASE_H diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index c321ed36b8..91d8520953 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -28,6 +28,7 @@ #include "compiler/lowering/ets/convertPrimitiveCastMethodCall.h" #include "compiler/lowering/ets/declareOverloadLowering.h" #include "compiler/lowering/ets/cfgBuilderPhase.h" +#include "compiler/lowering/ets/declGenPhase.h" #include "compiler/lowering/ets/defaultParametersInConstructorLowering.h" #include "compiler/lowering/ets/defaultParametersLowering.h" #include "compiler/lowering/ets/enumLowering.h" @@ -121,7 +122,9 @@ std::vector GetETSPhaseList() new AnnotationCopyLowering, // please DO NOT change order of these two phases: checkerPhase and pluginsAfterCheck new CheckerPhase, - // pluginsAfterCheck has to go right after checkerPhase, nothing should be between them + // Dump declaration right after checker + new DeclGenPhase, + // pluginsAfterCheck has to go right after checkerPhase new PluginPhase {g_pluginsAfterCheck, ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}, // new ConvertPrimitiveCastMethodCall, new AnnotationCopyPostLowering, diff --git a/ets2panda/docs/cheatsheet.md b/ets2panda/docs/cheatsheet.md index 48e7146f52..6810c0711a 100644 --- a/ets2panda/docs/cheatsheet.md +++ b/ets2panda/docs/cheatsheet.md @@ -139,7 +139,7 @@ in each module that we compile. The default config file looks like this: "import_tests": ["/path/to/static_core/tools/es2panda/test/parser/ets/import_tests"], "dynamic_import_tests": ["/path/to/static_core/tools/es2panda/test/parser/ets/dynamic_import_tests"] }, - "dynamicPaths": { + "dependencies": { "dynamic_import_tests": {"language": "js", "hasDecl": false}, "/path/to/static_core/tools/es2panda/test/parser/ets/dynamic_import_tests": {"language": "js", "hasDecl": true} } diff --git a/ets2panda/docs/import_export.md b/ets2panda/docs/import_export.md index d0c1c44213..9277ed82b6 100644 --- a/ets2panda/docs/import_export.md +++ b/ets2panda/docs/import_export.md @@ -113,7 +113,7 @@ The *importPath* is a string literal which can be points to a module (separate m Resolving these paths within the compiler is the responsibility of the *importPathManager*. In the process of parsing an import path, the string literal will be passed to the importPathManager which will resolve it as an absolute path and adds it to an own list, called *parseList_.* The latter list serves to let the compiler know what still needs to be parsed (handle and avoid duplications), and this list will be requested and traversed during the *ParseSources* call. The importPathManager also handles errors that can be caught before parsing, for example non-existent, incorrectly specified import paths, but not errors that can only be found after parsing (for example, the package folder should contains only package files that use the same package directive, etc.) -The importPath with the resolved path and two additional information - which is the language information and whether the imported element has a declaration or not - , will be stored in an ImportSource instance. The latter two information can be set under the dynamicPaths tag in arktsconfig.json, otherwise they will be assigned a default value (the lang member will be specified from the extension, hasDecl member will be true). This instance will be passed as a parameter during the allocation of the *ETSImportDeclaration* AST node, as well as the specifiers list resolved from the binding forms explained in the next section and the import kind (type or value). +The importPath with the resolved path and two additional information - which is the language information and whether the imported element has a declaration or not - , will be stored in an ImportSource instance. The latter two information can be set under the dependencies tag in arktsconfig.json, otherwise they will be assigned a default value (the lang member will be specified from the extension, hasDecl member will be true). This instance will be passed as a parameter during the allocation of the *ETSImportDeclaration* AST node, as well as the specifiers list resolved from the binding forms explained in the next section and the import kind (type or value). ## 5.2. Handle binding forms (allBinding|selectiveBindings|defaultBinding|typeBinding) diff --git a/ets2panda/driver/build_system/src/build/generate_arktsconfig.ts b/ets2panda/driver/build_system/src/build/generate_arktsconfig.ts index b4d889ba36..1028897d9c 100644 --- a/ets2panda/driver/build_system/src/build/generate_arktsconfig.ts +++ b/ets2panda/driver/build_system/src/build/generate_arktsconfig.ts @@ -44,9 +44,9 @@ import { sdkConfigPrefix, } from '../pre_define'; -interface DynamicPathItem { +interface DependencyItem { language: string, - declPath: string, + path: string, ohmUrl: string } @@ -55,9 +55,8 @@ interface ArkTSConfigObject { package: string, baseUrl: string, paths: Record; - dependencies: string[] | undefined; entry?: string; - dynamicPaths: Record; + dependencies: Record; useEmptyPackage?: boolean; } }; @@ -197,20 +196,13 @@ export class ArkTSConfigGenerator { } } - private getDependenciesSection(moduleInfo: ModuleInfo, dependenciesSection: string[]): void { - let depModules: Map = moduleInfo.staticDepModuleInfos; - depModules.forEach((depModuleInfo: ModuleInfo) => { - dependenciesSection.push(depModuleInfo.arktsConfigFile); - }); - } - private getOhmurl(file: string, moduleInfo: ModuleInfo): string { let unixFilePath: string = file.replace(/\\/g, '/'); let ohmurl: string = moduleInfo.packageName + '/' + unixFilePath; return changeFileExtension(ohmurl, ''); } - private getDynamicPathSection(moduleInfo: ModuleInfo, dynamicPathSection: Record): void { + private getDependenciesSection(moduleInfo: ModuleInfo, dependenciesection: Record): void { let depModules: Map = moduleInfo.dynamicDepModuleInfos; depModules.forEach((depModuleInfo: ModuleInfo) => { @@ -222,16 +214,16 @@ export class ArkTSConfigGenerator { let declFilesObject = JSON.parse(fs.readFileSync(depModuleInfo.declFilesPath, 'utf-8')); Object.keys(declFilesObject.files).forEach((file: string) => { let ohmurl: string = this.getOhmurl(file, depModuleInfo); - dynamicPathSection[ohmurl] = { + dependenciesection[ohmurl] = { language: 'js', - declPath: declFilesObject.files[file].declPath, + path: declFilesObject.files[file].declPath, ohmUrl: declFilesObject.files[file].ohmUrl }; let absFilePath: string = path.resolve(depModuleInfo.moduleRootPath, file); let entryFileWithoutExtension: string = changeFileExtension(depModuleInfo.entryFile, ''); if (absFilePath === entryFileWithoutExtension) { - dynamicPathSection[depModuleInfo.packageName] = dynamicPathSection[ohmurl]; + dependenciesection[depModuleInfo.packageName] = dependenciesection[ohmurl]; } }); }); @@ -250,25 +242,21 @@ export class ArkTSConfigGenerator { this.logger.printErrorAndExit(logData); } let pathSection = this.getPathSection(moduleInfo); - let dependenciesSection: string[] = []; - this.getDependenciesSection(moduleInfo, dependenciesSection); - this.getAllFilesToPathSectionForHybrid(moduleInfo, buildConfig); - - let dynamicPathSection: Record = {}; + this.getAllFilesToPathSectionForHybrid(moduleInfo, buildConfig); + let dependenciesection: Record = {}; if (!enableDeclgenEts2Ts) { - this.getDynamicPathSection(moduleInfo, dynamicPathSection); + this.getDependenciesSection(moduleInfo, dependenciesection); } - this.processAlias(moduleInfo, dynamicPathSection); + this.processAlias(moduleInfo, dependenciesection); let baseUrl: string = path.resolve(moduleInfo.moduleRootPath, moduleInfo.sourceRoots[0]); let arktsConfig: ArkTSConfigObject = { compilerOptions: { package: moduleInfo.packageName, baseUrl: baseUrl, paths: pathSection, - dependencies: dependenciesSection.length === 0 ? undefined : dependenciesSection, entry: moduleInfo.entryFile, - dynamicPaths: dynamicPathSection + dependencies: dependenciesection } }; @@ -292,20 +280,20 @@ export class ArkTSConfigGenerator { fs.writeFileSync(moduleInfo.arktsConfigFile, JSON.stringify(arktsConfig, null, 2), 'utf-8'); } - private processAlias(moduleInfo: ModuleInfo, dynamicPathSection: Record): void { + private processAlias(moduleInfo: ModuleInfo, dependencySection: Record): void { const aliasForPkg: Map | undefined = this.aliasConfig?.get(moduleInfo.packageName); aliasForPkg?.forEach((aliasConfig, aliasName) => { if (aliasConfig.isStatic || aliasConfig.originalAPIName.startsWith('@kit')) { this.processStaticAlias(aliasName, aliasConfig); } else { - this.processDynamicAlias(aliasName, aliasConfig, dynamicPathSection); + this.processDynamicAlias(aliasName, aliasConfig, dependencySection); } }); this.dynamicSDKPaths.forEach(basePath => { if (fs.existsSync(basePath)) { - this.traverseDynamicPath(basePath, '', false, dynamicPathSection); + this.traverseDynamicPath(basePath, '', false, dependencySection); } else { this.logger.printWarn(`sdk path ${basePath} not exist.`); } @@ -384,7 +372,7 @@ export class ArkTSConfigGenerator { } } - private processDynamicAlias(aliasName: string, aliasConfig: AliasConfig, dynamicPathSection: Record) { + private processDynamicAlias(aliasName: string, aliasConfig: AliasConfig, dependencySection: Record) { const declPath = getInteropFilePathByApi(aliasConfig.originalAPIName, this.dynamicSDKPaths); if (declPath === '') { return; @@ -396,9 +384,9 @@ export class ArkTSConfigGenerator { ); this.logger.printError(logData); } - dynamicPathSection[aliasName] = { + dependencySection[aliasName] = { language: 'js', - declPath: declPath, + path: declPath, ohmUrl: getOhmurlByApi(aliasConfig.originalAPIName) } } diff --git a/ets2panda/evaluate/entityDeclarator.cpp b/ets2panda/evaluate/entityDeclarator.cpp index acd955e308..02631fd53d 100644 --- a/ets2panda/evaluate/entityDeclarator.cpp +++ b/ets2panda/evaluate/entityDeclarator.cpp @@ -86,7 +86,7 @@ ir::ETSImportDeclaration *EntityDeclarator::CreateIrImport(util::StringView path auto *spec = checker->AllocNode(imported, local); ArenaVector specifiers(1, spec, allocator->Adapter()); - return checker->AllocNode(source, importMetadata, std::move(specifiers)); + return checker->AllocNode(source, std::move(importMetadata), std::move(specifiers)); } void EntityDeclarator::InsertImportStatement(ir::Statement *importStatement, parser::Program *importerProgram) diff --git a/ets2panda/ir/ets/etsImportDeclaration.h b/ets2panda/ir/ets/etsImportDeclaration.h index 7f7e56683b..dc5d6d8094 100644 --- a/ets2panda/ir/ets/etsImportDeclaration.h +++ b/ets2panda/ir/ets/etsImportDeclaration.h @@ -27,9 +27,9 @@ class StringLiteral; class ETSImportDeclaration : public ImportDeclaration { public: - ETSImportDeclaration(ir::StringLiteral *importPath, util::ImportPathManager::ImportMetadata importMetadata, + ETSImportDeclaration(ir::StringLiteral *importPath, util::ImportPathManager::ImportMetadata &&importMetadata, ArenaVector &&specifiers, const ImportKinds importKinds = ImportKinds::ALL) - : ImportDeclaration(importPath, std::move(specifiers), importKinds), importMetadata_(importMetadata) + : ImportDeclaration(importPath, std::move(specifiers), importKinds), importMetadata_(std::move(importMetadata)) { SetType(AstNodeType::ETS_IMPORT_DECLARATION); } diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index efb296e96b..7296238a19 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -361,15 +361,23 @@ std::vector ETSParser::SearchForNotParsed(ArenaVectorMarkAsParsed(data.resolvedSource); return programs; } - util::DiagnosticMessageParams diagParams = {std::string(parseCandidate)}; - std::ifstream inputStream {std::string(parseCandidate)}; + + std::string parseCandidateStr {parseCandidate}; + util::DiagnosticMessageParams diagParams = {parseCandidateStr}; + std::ifstream inputStream {parseCandidateStr}; if (!inputStream) { DiagnosticEngine().LogDiagnostic(diagnostic::OPEN_FAILED, diagParams); return programs; // Error processing. } std::stringstream ss; ss << inputStream.rdbuf(); - std::string externalSource = ss.str(); + std::string externalSource; + if (data.IsExternalBinaryImport()) { + externalSource = data.declText; + } else { + externalSource = ss.str(); + } + auto preservedLang = GetContext().SetLanguage(data.lang); auto extSrc = Allocator()->New(externalSource, Allocator()); importPathManager_->MarkAsParsed(data.resolvedSource); diff --git a/ets2panda/parser/program/program.h b/ets2panda/parser/program/program.h index c29543942c..c560db7fca 100644 --- a/ets2panda/parser/program/program.h +++ b/ets2panda/parser/program/program.h @@ -48,7 +48,6 @@ class Checker; namespace ark::es2panda::parser { enum class ScriptKind { SCRIPT, MODULE, STDLIB }; -enum EntityType { CLASS_PROPERTY = 0, METHOD_DEFINITION = 1, CLASS_DEFINITION = 2, TS_INTERFACE_DECLARATION = 3 }; #ifndef NDEBUG constexpr uint32_t POISON_VALUE {0x12346789}; @@ -311,19 +310,8 @@ public: void AddNodeToETSNolintCollection(const ir::AstNode *node, const std::set &warningsCollection); bool NodeContainsETSNolint(const ir::AstNode *node, ETSWarnings warning); - std::vector> &DeclGenExportNodes() - { - // NOTE: ExportNodes is not supported now. - return declGenExportNodes_; - } - bool MergeExternalSource(const ExternalSource *externalSource); - void AddDeclGenExportNode(const std::string &declGenExportStr, ir::AstNode *node) - { - declGenExportNodes_.emplace_back(declGenExportStr, node); - } - // The name "IsDied", because correct value of canary is a necessary condition for the life of "Program", but // not sufficient bool IsDied() const @@ -388,7 +376,6 @@ private: bool isASTlowered_ {}; lexer::SourcePosition packageStartPosition_ {}; compiler::CFG *cfg_; - std::vector> declGenExportNodes_; ArenaVector functionScopes_; std::unordered_map> fileDependencies_; diff --git a/ets2panda/test/tsconfig/test-decl/check-decl-path/arktsconfig.in.decl.json b/ets2panda/test/tsconfig/test-decl/check-decl-path/arktsconfig.in.decl.json index abc17863c9..ee7ac03b2c 100644 --- a/ets2panda/test/tsconfig/test-decl/check-decl-path/arktsconfig.in.decl.json +++ b/ets2panda/test/tsconfig/test-decl/check-decl-path/arktsconfig.in.decl.json @@ -5,8 +5,8 @@ "escompat": ["${PANDA_ROOT}/plugins/ets/stdlib/escompat"], "std": ["${PANDA_ROOT}/plugins/ets/stdlib/std"] }, - "dynamicPaths": { - "js": { "language": "js", "declPath": "${CMAKE_CURRENT_SOURCE_DIR}/wrong-path/js/index.ets", "ohmUrl": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index" } + "dependencies": { + "js": { "language": "js", "path": "${CMAKE_CURRENT_SOURCE_DIR}/wrong-path/js/index.ets", "ohmUrl": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index" } } } } \ No newline at end of file diff --git a/ets2panda/test/tsconfig/test-decl/check-export-decl/arktsconfig.in.decl.json b/ets2panda/test/tsconfig/test-decl/check-export-decl/arktsconfig.in.decl.json index 3e875c427d..030c6d78f4 100644 --- a/ets2panda/test/tsconfig/test-decl/check-export-decl/arktsconfig.in.decl.json +++ b/ets2panda/test/tsconfig/test-decl/check-export-decl/arktsconfig.in.decl.json @@ -5,8 +5,8 @@ "escompat": ["${PANDA_ROOT}/plugins/ets/stdlib/escompat"], "std": ["${PANDA_ROOT}/plugins/ets/stdlib/std"] }, - "dynamicPaths": { - "js": { "language": "js", "declPath": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index.ets", "ohmUrl": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index" } + "dependencies": { + "js": { "language": "js", "path": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index.ets", "ohmUrl": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index" } } } } diff --git a/ets2panda/test/tsconfig/test-decl/check-extend-dynamic/arktsconfig.in.decl.json b/ets2panda/test/tsconfig/test-decl/check-extend-dynamic/arktsconfig.in.decl.json index 3e875c427d..030c6d78f4 100644 --- a/ets2panda/test/tsconfig/test-decl/check-extend-dynamic/arktsconfig.in.decl.json +++ b/ets2panda/test/tsconfig/test-decl/check-extend-dynamic/arktsconfig.in.decl.json @@ -5,8 +5,8 @@ "escompat": ["${PANDA_ROOT}/plugins/ets/stdlib/escompat"], "std": ["${PANDA_ROOT}/plugins/ets/stdlib/std"] }, - "dynamicPaths": { - "js": { "language": "js", "declPath": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index.ets", "ohmUrl": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index" } + "dependencies": { + "js": { "language": "js", "path": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index.ets", "ohmUrl": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index" } } } } diff --git a/ets2panda/test/tsconfig/test-decl/resolve-dynamic-paths/arktsconfig.in.decl.json b/ets2panda/test/tsconfig/test-decl/resolve-dynamic-paths/arktsconfig.in.decl.json index 3e875c427d..030c6d78f4 100644 --- a/ets2panda/test/tsconfig/test-decl/resolve-dynamic-paths/arktsconfig.in.decl.json +++ b/ets2panda/test/tsconfig/test-decl/resolve-dynamic-paths/arktsconfig.in.decl.json @@ -5,8 +5,8 @@ "escompat": ["${PANDA_ROOT}/plugins/ets/stdlib/escompat"], "std": ["${PANDA_ROOT}/plugins/ets/stdlib/std"] }, - "dynamicPaths": { - "js": { "language": "js", "declPath": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index.ets", "ohmUrl": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index" } + "dependencies": { + "js": { "language": "js", "path": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index.ets", "ohmUrl": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index" } } } } diff --git a/ets2panda/test/tsconfig/test-decl/typecheck-decl/arktsconfig.in.decl.json b/ets2panda/test/tsconfig/test-decl/typecheck-decl/arktsconfig.in.decl.json index 3e875c427d..030c6d78f4 100644 --- a/ets2panda/test/tsconfig/test-decl/typecheck-decl/arktsconfig.in.decl.json +++ b/ets2panda/test/tsconfig/test-decl/typecheck-decl/arktsconfig.in.decl.json @@ -5,8 +5,8 @@ "escompat": ["${PANDA_ROOT}/plugins/ets/stdlib/escompat"], "std": ["${PANDA_ROOT}/plugins/ets/stdlib/std"] }, - "dynamicPaths": { - "js": { "language": "js", "declPath": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index.ets", "ohmUrl": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index" } + "dependencies": { + "js": { "language": "js", "path": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index.ets", "ohmUrl": "${CMAKE_CURRENT_SOURCE_DIR}/${project}/js/index" } } } } diff --git a/ets2panda/test/unit/arktsconfig-parser/arktsconfig_include.cpp b/ets2panda/test/unit/arktsconfig-parser/arktsconfig_include.cpp index 73e5d7bf6e..ac4c43adef 100644 --- a/ets2panda/test/unit/arktsconfig-parser/arktsconfig_include.cpp +++ b/ets2panda/test/unit/arktsconfig-parser/arktsconfig_include.cpp @@ -66,8 +66,7 @@ TEST_P(ArkTsConfigInclude, CheckInclude) auto param = GetParam(); ark::es2panda::util::DiagnosticEngine de; auto config = ark::es2panda::ArkTsConfig {*param.path, de}; - std::unordered_set parsedSet; - ASSERT_EQ(config.Parse(parsedSet), param.expected); + ASSERT_EQ(config.Parse(), param.expected); } INSTANTIATE_TEST_SUITE_P(ArkTsConfigIncludeSuite, ArkTsConfigInclude, diff --git a/ets2panda/test/unit/dynamic/dynamic_call_test.cpp b/ets2panda/test/unit/dynamic/dynamic_call_test.cpp index 2d2494db78..6adab4bdb4 100644 --- a/ets2panda/test/unit/dynamic/dynamic_call_test.cpp +++ b/ets2panda/test/unit/dynamic/dynamic_call_test.cpp @@ -88,7 +88,7 @@ public: specifiers.emplace_back(specifier); util::ImportPathManager::ImportMetadata importMetadata {util::ImportFlags::NONE, Language::Id::JS, "", "", ""}; auto importDecl = util::NodeAllocator::Alloc( - Allocator(), Allocator()->New("/tmp"), importMetadata, std::move(specifiers)); + Allocator(), Allocator()->New("/tmp"), std::move(importMetadata), std::move(specifiers)); compiler::InitScopesPhaseETS::RunExternalNode(importDecl, varbinder); varbinder->BuildImportDeclaration(importDecl); auto var = varbinder->TopScope()->Find(specifierName); diff --git a/ets2panda/test/unit/lsp/get_compiler_options_diagnostics_test.cpp b/ets2panda/test/unit/lsp/get_compiler_options_diagnostics_test.cpp index b53807cd62..03bea20317 100644 --- a/ets2panda/test/unit/lsp/get_compiler_options_diagnostics_test.cpp +++ b/ets2panda/test/unit/lsp/get_compiler_options_diagnostics_test.cpp @@ -61,8 +61,7 @@ public: ark::es2panda::util::DiagnosticEngine *diagnosticEngine = reinterpret_cast(ctx)->diagnosticEngine; auto config = ark::es2panda::ArkTsConfig {filePaths[1], *diagnosticEngine}; - std::unordered_set parsedConfigPath; - config.Parse(parsedConfigPath); + config.Parse(); ark::es2panda::lsp::GetOptionDiagnostics(ctx, diagnostics); initializer.DestroyContext(ctx); @@ -279,10 +278,10 @@ function A(a:number, b:number) { "paths": { "std": ["./path1"] }, - "dynamicPaths": { + "dependencies": { "dynamic_import_tests": { "language": "invalid_lang", - "hasDecl": true + "path": "path.d.ets" } } } @@ -317,10 +316,10 @@ function A(a:number, b:number) { "paths": { "std": ["./path1"] }, - "dynamicPaths": { + "dependencies": { "dynamic_import_tests": { "language": "ts", - "hasDecl": true + "path": "path.d.ets" } } } diff --git a/ets2panda/test/unit/plugin/CMakeLists.txt b/ets2panda/test/unit/plugin/CMakeLists.txt index 672aff08e4..09b82624dd 100644 --- a/ets2panda/test/unit/plugin/CMakeLists.txt +++ b/ets2panda/test/unit/plugin/CMakeLists.txt @@ -105,7 +105,6 @@ set(PLUGIN_TESTS "plugin_proceed_to_state_update_function_expression compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" "plugin_proceed_to_state_create_ets_new_expression compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" "plugin_proceed_to_state_log_diagnostic_with_suggestion compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" - "use_plugin_to_test_export_table compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" "plugin_proceed_to_state_check_jsdoc compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" "plugin_proceed_to_state_test_global_func_call_dump compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" "plugin_proceed_to_state_test_interface_duplicate_setter compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" @@ -134,19 +133,12 @@ foreach(TEST_DATA IN ITEMS ${PLUGIN_TESTS}) endif() panda_target_include_directories(${TEST_NAME} PRIVATE ${ES2PANDA_PATH} - PRIVATE ${PANDA_ROOT}/libpandafile - PRIVATE ${PANDA_ROOT}/assembler PRIVATE ${OUTPUT_DIR} PUBLIC ${CMAKE_CURRENT_BINARY_DIR} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} - PUBLIC ${CMAKE_SOURCE_DIR}/libpandabase - PUBLIC ${CMAKE_SOURCE_DIR}/runtime - PUBLIC ${CMAKE_BINARY_DIR}/libpandabase - PUBLIC ${CMAKE_BINARY_DIR}/libpandafile/include - PUBLIC ${CMAKE_BINARY_DIR}/abc2program ${CMAKE_BINARY_DIR} ) - panda_target_link_libraries(${TEST_NAME} es2panda-public arkassembler arkbase arkfile abc2program) + panda_target_link_libraries(${TEST_NAME} es2panda-public) endforeach() add_custom_target(es2panda-plugin-test) diff --git a/ets2panda/test/unit/plugin/use_plugin_to_test_export_table.cpp b/ets2panda/test/unit/plugin/use_plugin_to_test_export_table.cpp deleted file mode 100644 index 1bfb5a30ef..0000000000 --- a/ets2panda/test/unit/plugin/use_plugin_to_test_export_table.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Copyright (c) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include "file.h" -#include "macros.h" -#include "os/file.h" -#include "public/es2panda_lib.h" -#include "util.h" -#include "parser/program/program.h" -#include "ir/statements/blockStatement.h" -#include "ir/astNode.h" -#include "ir/statements/classDeclaration.h" -#include "ir/base/classDefinition.h" -#include "ir/base/methodDefinition.h" -#include "public/public.h" -#include "util/options.h" -#include "abc2program/abc2program_driver.h" - -// NOLINTBEGIN - -static es2panda_Impl *impl = nullptr; - -namespace { -constexpr size_t CLASS_DEFINITION_INDEX = 1; -constexpr size_t METHOD_DEFINITION_INDEX = 0; -constexpr size_t METHOD_BODY_INDEX = 2; - -enum Const { - LITERAL_INDEX_0 = 0, - LITERAL_INDEX_1 = 1, - LITERAL_INDEX_2 = 2, - LITERAL_INDEX_3 = 3, - LITERAL_INDEX_4 = 4, - LITERAL_INDEX_5 = 5, - EXPECTED_VALUE_1 = 1, - EXPECTED_VALUE_2 = 2, -}; - -const std::string SOURCE_CODE = - " function foo():void {\n" - " }\n" - " class A{}\n"; - -const std::string EXPECTED_CLASS_DEFINITION = "class A {\n public constructor() {}\n \n}\n"; - -const std::string EXPECTED_METHOD_DEFINITION = "function foo(): void {}\n"; - -int CheckLiteralValues(ark::es2panda::public_lib::Context *ctx, const ark::pandasm::Program &prog) -{ - auto file = ark::panda_file::OpenPandaFile(ctx->config->options->GetOutput()); - if (!file) { - return TEST_ERROR_CODE; - } - - auto literalArrIt = prog.literalarrayTable.find("0"); - if (literalArrIt == prog.literalarrayTable.end()) { - return TEST_ERROR_CODE; - } - auto &literalArr = literalArrIt->second.literals; - if (EXPECTED_VALUE_2 != std::get(literalArr[LITERAL_INDEX_1].value) || - EXPECTED_VALUE_1 != std::get(literalArr[LITERAL_INDEX_4].value)) { - return TEST_ERROR_CODE; - } - - const auto offsetA = std::get(literalArr[LITERAL_INDEX_0].value); - const auto stringDataA = file->GetStringData(ark::panda_file::File::EntityId(offsetA)); - auto stringA = std::string(reinterpret_cast(stringDataA.data), stringDataA.utf16Length); - - const auto offsetFoo = std::get(literalArr[LITERAL_INDEX_3].value); - const auto stringDataFoo = file->GetStringData(ark::panda_file::File::EntityId(offsetFoo)); - auto stringFoo = std::string(reinterpret_cast(stringDataFoo.data), stringDataFoo.utf16Length); - - if (stringA != EXPECTED_CLASS_DEFINITION) { - return TEST_ERROR_CODE; - } - - if (stringFoo != EXPECTED_METHOD_DEFINITION) { - return TEST_ERROR_CODE; - } - - return 0; -} - -void ProcessProgram(ark::es2panda::parser::Program *programPtr) -{ - auto *classDef = programPtr->Ast()->Statements()[CLASS_DEFINITION_INDEX]->AsClassDeclaration()->Definition(); - programPtr->AddDeclGenExportNode(classDef->DumpEtsSrc(), classDef); - - auto *methodDef = programPtr->Ast() - ->Statements()[METHOD_DEFINITION_INDEX] - ->AsClassDeclaration() - ->Definition() - ->AsClassDefinition() - ->Body()[METHOD_BODY_INDEX] - ->AsMethodDefinition(); - programPtr->AddDeclGenExportNode(methodDef->DumpEtsSrc(), methodDef); -} -} // namespace - -int main(int argc, char **argv) -{ - if (argc < MIN_ARGC) { - return INVALID_ARGC_ERROR_CODE; - } - - if (GetImpl() == nullptr) { - return NULLPTR_IMPL_ERROR_CODE; - } - impl = GetImpl(); - const char **args = const_cast(&(argv[1])); - auto config = impl->CreateConfig(argc - 1, args); - auto config_ = reinterpret_cast(config); - const_cast(config_->options)->SetWithExportTable(true); - auto context = impl->CreateContextFromString(config, SOURCE_CODE.data(), argv[argc - 1]); - if (context == nullptr) { - return NULLPTR_CONTEXT_ERROR_CODE; - } - - impl->ProceedToState(context, ES2PANDA_STATE_PARSED); - CheckForErrors("PARSE", context); - - impl->ProceedToState(context, ES2PANDA_STATE_BOUND); - CheckForErrors("BOUND", context); - - impl->ProceedToState(context, ES2PANDA_STATE_CHECKED); - CheckForErrors("CHECKED", context); - - auto program = impl->ContextProgram(context); - auto programPtr = reinterpret_cast(program); - ProcessProgram(programPtr); - - impl->ProceedToState(context, ES2PANDA_STATE_LOWERED); - CheckForErrors("LOWERED", context); - - impl->ProceedToState(context, ES2PANDA_STATE_ASM_GENERATED); - CheckForErrors("ASM", context); - - impl->ProceedToState(context, ES2PANDA_STATE_BIN_GENERATED); - CheckForErrors("BIN", context); - - auto *ctx = reinterpret_cast(context); - auto abc2program = new ark::abc2program::Abc2ProgramDriver(); - abc2program->Compile("./use_plugin_to_test_export_table.abc"); - auto res = CheckLiteralValues(ctx, abc2program->GetProgram()); - impl->DestroyConfig(config); - return res; -} - -// NOLINTEND \ No newline at end of file diff --git a/ets2panda/util/arktsconfig.cpp b/ets2panda/util/arktsconfig.cpp index d58d6220f2..7ee0d89b8d 100644 --- a/ets2panda/util/arktsconfig.cpp +++ b/ets2panda/util/arktsconfig.cpp @@ -164,8 +164,7 @@ static std::string ResolveConfigLocation(const std::string &relPath, const std:: } std::optional ArkTsConfig::ParseExtends(const std::string &configPath, const std::string &extends, - const std::string &configDir, - std::unordered_set &parsedConfigPath) + const std::string &configDir) { auto basePath = ResolveConfigLocation(extends, configDir); if (!Check(!basePath.empty(), diagnostic::UNRESOLVABLE_CONFIG_PATH, {extends})) { @@ -177,7 +176,7 @@ std::optional ArkTsConfig::ParseExtends(const std::string &configPa } auto base = ArkTsConfig(basePath, diagnosticEngine_); - if (!Check(base.Parse(parsedConfigPath), diagnostic::WRONG_BASE_CONFIG, {extends})) { + if (!Check(base.Parse(), diagnostic::WRONG_BASE_CONFIG, {extends})) { return {}; } @@ -185,19 +184,18 @@ std::optional ArkTsConfig::ParseExtends(const std::string &configPa } #endif // ARKTSCONFIG_USE_FILESYSTEM -static std::string ValidDynamicLanguages() +static std::string ValidLanguages() { JsonArrayBuilder builder; for (auto &l : Language::All()) { - if (l.IsDynamic()) { - builder.Add(l.ToString()); - } + builder.Add(l.ToString()); } return std::move(builder).Build(); } bool ArkTsConfig::ParsePaths(const JsonObject::JsonObjPointer *options, PathsMap &pathsMap, const std::string &baseUrl) { + // Paths semantic should be simplified #23246 auto paths = options->get()->GetValue("paths"); if (paths == nullptr) { return true; @@ -227,70 +225,82 @@ bool ArkTsConfig::ParsePaths(const JsonObject::JsonObjPointer *options, PathsMap return true; } -static constexpr auto LANGUAGE = "language"; // CC-OFF(G.NAM.03-CPP) project code style -static constexpr auto DECL_PATH = "declPath"; // CC-OFF(G.NAM.03-CPP) project code style -static constexpr auto OHM_URL = "ohmUrl"; // CC-OFF(G.NAM.03-CPP) project code style - -bool ArkTsConfig::ParseDynamicPaths(const JsonObject::JsonObjPointer *options, - std::map &dynamicPathsMap, - const std::string &baseUrl) -{ - if (options == nullptr) { - return true; - } - auto dynamicPaths = options->get()->GetValue("dynamicPaths"); - if (dynamicPaths == nullptr) { - return true; - } - for (size_t keyIdx = 0; keyIdx < dynamicPaths->get()->GetSize(); ++keyIdx) { - auto &key = dynamicPaths->get()->GetKeyByIndex(keyIdx); - auto data = dynamicPaths->get()->GetValue(key); - if (!ParseSingleDynamicPath(key, data, dynamicPathsMap, baseUrl)) { - return false; - } - } - return true; -} +static constexpr auto LANGUAGE = "language"; // CC-OFF(G.NAM.03-CPP) project code style +static constexpr auto PATH = "path"; // CC-OFF(G.NAM.03-CPP) project code style +static constexpr auto OHM_URL = "ohmUrl"; // CC-OFF(G.NAM.03-CPP) project code style -bool ArkTsConfig::ParseSingleDynamicPath(const std::string &key, const JsonObject::JsonObjPointer *data, - std::map &dynamicPathsMap, - const std::string &baseUrl) +bool ArkTsConfig::ParseDependency(size_t keyIdx, const std::unique_ptr *dependencies, + std::map &dependenciesMap) { + // NOTE: arktsconfig.json structure check should be added #22687 + auto &key = dependencies->get()->GetKeyByIndex(keyIdx); if (IsAbsolute(key)) { - diagnosticEngine_.LogDiagnostic(diagnostic::DYNAMIC_PATHS_ABSOLUTE, util::DiagnosticMessageParams {key}); + diagnosticEngine_.LogDiagnostic(diagnostic::DEPENDENCIES_ABSOLUTE, util::DiagnosticMessageParams {key}); } - if (!Check(data != nullptr, diagnostic::INVALID_VALUE, {"dynamic path", key})) { + + auto data = dependencies->get()->GetValue(key); + if (!Check(data != nullptr, diagnostic::INVALID_VALUE, {"dependency", key})) { return false; } + auto langValue = data->get()->GetValue(LANGUAGE); - if (!Check(langValue != nullptr, diagnostic::INVALID_LANGUAGE, {LANGUAGE, key, ValidDynamicLanguages()})) { - return false; + std::optional lang = std::nullopt; + if (langValue != nullptr) { + lang = Language::FromString(*langValue); + } else { + lang = Language {Language::Id::ETS}; } - auto lang = Language::FromString(*langValue); - if (!Check(lang && lang->IsDynamic(), diagnostic::INVALID_LANGUAGE, {LANGUAGE, key, ValidDynamicLanguages()})) { + const auto &diagParams = util::DiagnosticMessageParams {LANGUAGE, key, ValidLanguages()}; + if (!Check(lang != std::nullopt && lang->IsValid(), diagnostic::INVALID_LANGUAGE, diagParams)) { return false; } + auto isSupportLang = compiler::Signatures::Dynamic::IsSupported(*lang); - if (!Check(isSupportLang, diagnostic::UNSUPPORTED_LANGUAGE_FOR_INTEROP, {lang->ToString()})) { + if (lang->IsDynamic() && !Check(isSupportLang, diagnostic::UNSUPPORTED_LANGUAGE_FOR_INTEROP, {lang->ToString()})) { return false; } + auto ohmUrl = data->get()->GetValue(OHM_URL); - if (ohmUrl == nullptr) { + if (ohmUrl == nullptr && lang && lang->IsDynamic()) { diagnosticEngine_.LogDiagnostic(diagnostic::NO_OHMURL, util::DiagnosticMessageParams {key}); } std::string ohmUrlValue = (ohmUrl == nullptr) ? "" : *ohmUrl; - auto declPathValue = data->get()->GetValue(DECL_PATH); - std::string normalizedDeclPath {}; - if (declPathValue != nullptr) { - normalizedDeclPath = IsAbsolute(*declPathValue) ? ark::os::GetAbsolutePath(*declPathValue) - : MakeAbsolute(*declPathValue, baseUrl); - if (!Check(ark::os::IsFileExists(normalizedDeclPath), diagnostic::INVALID_DYNAMIC_PATH, {key})) { + + auto pathValue = data->get()->GetValue(PATH); + std::string normalizedPath {}; + // NOTE(itrubachev): path in dependencies must be mandatory. Need to fix interop tests + if (pathValue != nullptr) { + normalizedPath = + IsAbsolute(*pathValue) ? ark::os::GetAbsolutePath(*pathValue) : MakeAbsolute(*pathValue, baseUrl_); + if (!Check(ark::os::IsFileExists(normalizedPath), diagnostic::INVALID_PATH, {key})) { + return false; + } + } else { + // NOTE(itrubachev): path in dependencies must be mandatory. Now it can be not specified only for interop + if (!Check(lang && lang->IsDynamic(), diagnostic::INVALID_PATH, {key})) { + return false; + } + } + auto res = dependenciesMap.insert({key, ArkTsConfig::ExternalModuleData(*lang, normalizedPath, ohmUrlValue)}); + return Check(res.second, diagnostic::DUPLICATED_DEPENDENCIES, {normalizedPath, key}); +} + +bool ArkTsConfig::ParseDependencies(const JsonObject::JsonObjPointer *options, + std::map &dependenciesMap) +{ + if (options == nullptr) { + return true; + } + auto dependencies = options->get()->GetValue(DEPENDENCIES); + if (dependencies == nullptr) { + return true; + } + for (size_t keyIdx = 0; keyIdx < dependencies->get()->GetSize(); ++keyIdx) { + if (!ParseDependency(keyIdx, dependencies, dependenciesMap)) { return false; } } - auto res = dynamicPathsMap.insert( - {ark::os::NormalizePath(key), ArkTsConfig::DynamicImportData(*lang, normalizedDeclPath, ohmUrlValue)}); - return Check(res.second, diagnostic::DUPLICATED_DYNAMIC_PATH, {normalizedDeclPath, key}); + return true; } template @@ -314,19 +324,6 @@ bool ArkTsConfig::ParseCollection(const JsonObject *config, Collection &out, con return true; } -void ArkTsConfig::ResolveConfigDependencies(std::unordered_map> &dependencies, - std::vector &dependencyPaths, - std::unordered_set &parsedConfigPath) -{ - for (auto dependency : dependencyPaths) { - auto config = std::make_shared(std::string_view(dependency), diagnosticEngine_); - if (!Check(config->Parse(parsedConfigPath), diagnostic::EMPTY_LIST, {dependency})) { - continue; - } - dependencies.emplace(config->Package(), std::move(config)); - } -} - std::optional ArkTsConfig::ReadConfig(const std::string &path) { std::ifstream inputStream(path); @@ -346,27 +343,19 @@ static std::string ValueOrEmptyString(const JsonObject::JsonObjPointer *json, co } static void ResolvePathInDependenciesImpl(ArkTsConfig *arktsConfig, - std::map, CompareByLength> &paths, - std::unordered_map &entries) + std::map, CompareByLength> &paths) { for (const auto &dependencyPath : arktsConfig->Paths()) { paths.emplace(dependencyPath.first, dependencyPath.second); } - if (!arktsConfig->Entry().empty()) { - entries.emplace(arktsConfig->Package(), arktsConfig->Entry()); - } - for (const auto &config : arktsConfig->Dependencies()) { - ResolvePathInDependenciesImpl(config.second.get(), paths, entries); - } } void ArkTsConfig::ResolveAllDependenciesInArkTsConfig() { - ResolvePathInDependenciesImpl(this, paths_, entries_); + ResolvePathInDependenciesImpl(this, paths_); } -bool ArkTsConfig::ParseCompilerOptions(std::string &arktsConfigDir, std::unordered_set &parsedConfigPath, - const JsonObject *arktsConfig) +bool ArkTsConfig::ParseCompilerOptions(std::string &arktsConfigDir, const JsonObject *arktsConfig) { auto compilerOptions = arktsConfig->GetValue(COMPILER_OPTIONS); // Parse "package" @@ -377,45 +366,25 @@ bool ArkTsConfig::ParseCompilerOptions(std::string &arktsConfigDir, std::unorder outDir_ = MakeAbsolute(ValueOrEmptyString(compilerOptions, OUT_DIR), arktsConfigDir); rootDir_ = MakeAbsolute(ValueOrEmptyString(compilerOptions, ROOT_DIR), arktsConfigDir); - // Parse "entry" - if (compilerOptions->get()->HasKey(ENTRY)) { - entry_ = MakeAbsolute(ValueOrEmptyString(compilerOptions, ENTRY), baseUrl_); - } - // Parse "useUrl" if (compilerOptions->get()->HasKey(USE_EMPTY_PACKAGE)) { useUrl_ = *(compilerOptions->get()->GetValue(USE_EMPTY_PACKAGE)); } - // Parse "dependencies" - auto concatPath = [this](const auto &val) { return MakeAbsolute(val, baseUrl_); }; - std::vector dependencyPaths; - if (compilerOptions->get()->HasKey(DEPENDENCIES)) { - ParseCollection(compilerOptions->get(), dependencyPaths, DEPENDENCIES, concatPath); - } - if (!dependencyPaths.empty()) { - ResolveConfigDependencies(dependencies_, dependencyPaths, parsedConfigPath); - } // Parse "paths" if (!ParsePaths(compilerOptions, paths_, baseUrl_)) { return false; } - // Parse "dynamicPaths" - if (!ParseDynamicPaths(compilerOptions, dynamicPaths_, baseUrl_)) { + // Parse "dependencies" + if (!ParseDependencies(compilerOptions, dependencies_)) { return false; } return true; } // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP, G.FUD.05) solid logic -bool ArkTsConfig::Parse(std::unordered_set &parsedConfigPath) +bool ArkTsConfig::Parse() { - // For circurlar dependencies, just skip parsing - if (parsedConfigPath.find(configPath_) != parsedConfigPath.end()) { - return true; - } - parsedConfigPath.emplace(configPath_); - ES2PANDA_ASSERT(!isParsed_); isParsed_ = true; auto arktsConfigDir = ParentPath(ark::os::GetAbsolutePath(configPath_)); @@ -439,7 +408,7 @@ bool ArkTsConfig::Parse(std::unordered_set &parsedConfigPath) if (!Check(extends != nullptr, diagnostic::INVALID_JSON_TYPE, {EXTENDS, "string"})) { return false; } - const auto &base = ParseExtends(configPath_, *extends, arktsConfigDir, parsedConfigPath); + const auto &base = ParseExtends(configPath_, *extends, arktsConfigDir); if (!base.has_value()) { return false; } @@ -448,8 +417,7 @@ bool ArkTsConfig::Parse(std::unordered_set &parsedConfigPath) #endif // ARKTSCONFIG_USE_FILESYSTEM // Parse "compilerOptions" - if (arktsConfig->HasKey(COMPILER_OPTIONS) && - !ParseCompilerOptions(arktsConfigDir, parsedConfigPath, arktsConfig.get())) { + if (arktsConfig->HasKey(COMPILER_OPTIONS) && !ParseCompilerOptions(arktsConfigDir, arktsConfig.get())) { return false; } @@ -514,13 +482,9 @@ std::optional ArkTsConfig::ResolvePath(std::string_view path, bool return std::nullopt; }; - auto tryResolveWithDynamicPaths = [this, &path]() -> std::optional { - auto normalizedPath = ark::os::NormalizePath(std::string(path)); - for (const auto &[dynPath, _] : dynamicPaths_) { - // NOTE(dkofanov): #23877. Fail, if there is no direct match of normalized dynamic module path. - // It may be worth to take an attempt to resolve 'path' as relative to some defined dynamicPath in order to - // keep 'arktsconfig.json's smaller. - if (normalizedPath == dynPath) { + auto tryResolveWithDependencies = [this, &path]() -> std::optional { + for (const auto &[dynPath, _] : dependencies_) { + if (path == dynPath) { return dynPath; } } @@ -528,7 +492,7 @@ std::optional ArkTsConfig::ResolvePath(std::string_view path, bool }; if (isDynamic) { - auto result = tryResolveWithDynamicPaths(); + auto result = tryResolveWithDependencies(); if (result != std::nullopt) { return result; } @@ -539,7 +503,7 @@ std::optional ArkTsConfig::ResolvePath(std::string_view path, bool if (result != std::nullopt) { return result; } - return tryResolveWithDynamicPaths(); + return tryResolveWithDependencies(); } #ifdef ARKTSCONFIG_USE_FILESYSTEM diff --git a/ets2panda/util/arktsconfig.h b/ets2panda/util/arktsconfig.h index fec474785a..a6ef154dee 100644 --- a/ets2panda/util/arktsconfig.h +++ b/ets2panda/util/arktsconfig.h @@ -89,10 +89,10 @@ public: }; #endif // ARKTSCONFIG_USE_FILESYSTEM - class DynamicImportData { + class ExternalModuleData { public: - explicit DynamicImportData(Language lang, std::string declPath, std::string ohmUrl) - : lang_(lang), declPath_(std::move(declPath)), ohmUrl_(std::move(ohmUrl)) + explicit ExternalModuleData(Language lang, std::string path, std::string ohmUrl) + : lang_(lang), path_(std::move(path)), ohmUrl_(std::move(ohmUrl)) { } @@ -101,9 +101,9 @@ public: return lang_; } - std::string_view DeclPath() const + std::string_view Path() const { - return declPath_; + return path_; } std::string_view OhmUrl() const @@ -113,7 +113,7 @@ public: private: Language lang_; - std::string declPath_ {}; + std::string path_ {}; std::string ohmUrl_ {}; }; @@ -121,7 +121,7 @@ public: : configPath_(configPath), diagnosticEngine_(de) { } - bool Parse(std::unordered_set &parsedConfigPath); + bool Parse(); std::optional ResolvePath(std::string_view path, bool isDynamic = false) const; @@ -148,22 +148,6 @@ public: { return outDir_; } - const std::unordered_map> &Dependencies() const - { - return dependencies_; - } - void ResetDependencies() - { - return dependencies_.clear(); - } - const std::string &Entry() const - { - return entry_; - } - const std::unordered_map &Entries() const - { - return entries_; - } const std::vector &Files() const { return files_; @@ -176,9 +160,9 @@ public: { return paths_; } - const std::map &DynamicPaths() const + const std::map &Dependencies() const { - return dynamicPaths_; + return dependencies_; } #ifdef ARKTSCONFIG_USE_FILESYSTEM const std::vector &Include() const @@ -194,23 +178,14 @@ public: bool Check(bool cond, const diagnostic::DiagnosticKind &diag, const util::DiagnosticMessageParams ¶ms); private: - bool ParseCompilerOptions(std::string &arktsConfigDir, std::unordered_set &parsedConfigPath, - const JsonObject *arktsConfig); + bool ParseCompilerOptions(std::string &arktsConfigDir, const JsonObject *arktsConfig); std::optional ParseExtends(const std::string &configPath, const std::string &extends, - const std::string &configDir, - std::unordered_set &parsedConfigPath); + const std::string &configDir); bool ParsePaths(const JsonObject::JsonObjPointer *options, PathsMap &pathsMap, const std::string &baseUrl); - bool ParseDynamicPaths(const JsonObject::JsonObjPointer *options, - std::map &dynamicPathsMap, - const std::string &baseUrl); - bool ParseSingleDynamicPath(const std::string &key, const JsonObject::JsonObjPointer *data, - std::map &dynamicPathsMap, - const std::string &baseUrl); + bool ParseDependencies(const JsonObject::JsonObjPointer *options, + std::map &dependenciesMap); template bool ParseCollection(const JsonObject *config, Collection &out, const std::string &target, Function &&constructor); - void ResolveConfigDependencies(std::unordered_map> &dependencies, - std::vector &dependencyPaths, - std::unordered_set &parsedConfigPath); std::optional ReadConfig(const std::string &path); private: @@ -225,9 +200,10 @@ private: static constexpr const char *OUT_DIR = "outDir"; static constexpr const char *ROOT_DIR = "rootDir"; static constexpr const char *DEPENDENCIES = "dependencies"; // CC-OFF(G.NAM.03,G.NAM.03-CPP) project code style - static constexpr const char *ENTRY = "entry"; // CC-OFF(G.NAM.03,G.NAM.03-CPP) project code style void Inherit(const ArkTsConfig &base); + bool ParseDependency(size_t keyIdx, const std::unique_ptr *dependencies, + std::map &dependenciesMap); bool isParsed_ = false; std::string configPath_; @@ -237,13 +213,9 @@ private: bool useUrl_ = false; std::string outDir_ {}; std::string rootDir_ {}; - std::string entry_ {}; PathsMap paths_ {}; - std::map dynamicPaths_ {}; + std::map dependencies_ {}; std::vector files_ {}; - std::unordered_map> dependencies_ {}; - // key: package name; value: entry's absolute path - std::unordered_map entries_; #ifdef ARKTSCONFIG_USE_FILESYSTEM std::vector include_ {}; std::vector exclude_ {}; diff --git a/ets2panda/util/diagnostic/arktsconfig_error.yaml b/ets2panda/util/diagnostic/arktsconfig_error.yaml index 2568bcd284..e03085e195 100644 --- a/ets2panda/util/diagnostic/arktsconfig_error.yaml +++ b/ets2panda/util/diagnostic/arktsconfig_error.yaml @@ -44,7 +44,7 @@ arkts_config_error: id: 8 message: Invalid {} value for '{}' with key '{}' -- name: DUPLICATED_DYNAMIC_PATH +- name: DUPLICATED_DEPENDENCIES id: 9 message: Duplicated dynamic path '{}' for key '{}' @@ -76,6 +76,10 @@ arkts_config_error: id: 16 message: Invalid destination file -- name: INVALID_DYNAMIC_PATH +- name: INVALID_PATH id: 17 - message: Invalid dynamic path '{}' + message: Invalid path for '{}' in dependencies + +- name: DEPENDENCIES_ABSOLUTE + id: 18 + message: "Don't use absolute path '{}' as key in 'dependencies'" \ No newline at end of file diff --git a/ets2panda/util/diagnostic/warning.yaml b/ets2panda/util/diagnostic/warning.yaml index ceea39765e..e8164fa885 100644 --- a/ets2panda/util/diagnostic/warning.yaml +++ b/ets2panda/util/diagnostic/warning.yaml @@ -48,10 +48,6 @@ warning: id: 9 message: "Type alias generic parameter '{}' is not used in type annotation" -- name: DYNAMIC_PATHS_ABSOLUTE - id: 10 - message: "Don't use absolute path '{}' as key in 'dynamicPaths'" - - name: NO_OHMURL id: 11 message: "'ohmUrl' for module '{}' wasn't specified" diff --git a/ets2panda/util/importPathManager.cpp b/ets2panda/util/importPathManager.cpp index ae0e0b61c6..248d985b52 100644 --- a/ets2panda/util/importPathManager.cpp +++ b/ets2panda/util/importPathManager.cpp @@ -25,6 +25,10 @@ #include "parser/program/program.h" #include "ir/expressions/literals/stringLiteral.h" +#include "abc2program_driver.h" +#include "checker/types/signature.h" +#include "compiler/lowering/ets/declGenPhase.h" + #ifdef USE_UNIX_SYSCALL #include #include @@ -58,6 +62,55 @@ static bool IsAbsolute(const std::string &path) #endif // ARKTSCONFIG_USE_FILESYSTEM } +void ImportPathManager::ProcessExternalModuleImport(ImportMetadata &importData) +{ + ES2PANDA_ASSERT(!IsAbsolute(std::string(importData.resolvedSource))); + 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 emptry "path" in dependencies, since in interop we allow imports without typecheck + if (!Helpers::EndsWith(std::string(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; + 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 = moduleName; + + 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 = moduleDeclarationAnno->GetElements()[0].GetValue()->GetAsScalar()->GetValue(); + importData.declText = declText; +} + ImportPathManager::ImportMetadata ImportPathManager::GatherImportMetadata(parser::Program *program, ImportFlags importFlags, ir::StringLiteral *importPath) @@ -68,7 +121,7 @@ ImportPathManager::ImportMetadata ImportPathManager::GatherImportMetadata(parser // instead of 'AbsoluteName'. isDynamic_ = program->ModuleInfo().isDeclForDynamicStaticInterop; auto curModulePath = isDynamic_ ? program->ModuleInfo().moduleName : program->AbsoluteName(); - auto [resolvedImportPath, resolvedIsDynamic] = ResolvePath(curModulePath.Utf8(), importPath); + auto [resolvedImportPath, resolvedIsExternalModule] = ResolvePath(curModulePath.Utf8(), importPath); if (resolvedImportPath.empty()) { ES2PANDA_ASSERT(diagnosticEngine_.IsAnyError()); return ImportMetadata {util::ImportFlags::NONE, Language::Id::COUNT, ERROR_LITERAL}; @@ -78,14 +131,8 @@ ImportPathManager::ImportMetadata ImportPathManager::GatherImportMetadata(parser ImportMetadata importData {importFlags}; importData.resolvedSource = resolvedImportPath; - if (resolvedIsDynamic) { - ES2PANDA_ASSERT(!IsAbsolute(std::string(importData.resolvedSource))); - auto it = arktsConfig_->DynamicPaths().find(std::string(importData.resolvedSource)); - ES2PANDA_ASSERT(it != arktsConfig_->DynamicPaths().cend()); - const auto &dynImportData = it->second; - importData.lang = dynImportData.GetLanguage().GetId(); - importData.declPath = dynImportData.DeclPath(); - importData.ohmUrl = dynImportData.OhmUrl(); + if (resolvedIsExternalModule) { + ProcessExternalModuleImport(importData); } else { ES2PANDA_ASSERT(IsAbsolute(std::string(importData.resolvedSource))); importData.lang = ToLanguage(program->Extension()).GetId(); @@ -126,10 +173,6 @@ ImportPathManager::ResolvedPathRes ImportPathManager::ResolvePath(std::string_vi diagnosticEngine_.LogDiagnostic(diagnostic::EMPTY_IMPORT_PATH, util::DiagnosticMessageParams {}); return {*importPath}; } - const auto &entriesMap = arktsConfig_->Entries(); - if (auto it = entriesMap.find(importPath->Str().Mutf8()); it != entriesMap.cend()) { - return {UString(it->second, allocator_).View().Utf8()}; - } if (IsRelativePath(*importPath)) { const size_t pos = curModulePath.find_last_of("/\\"); ES2PANDA_ASSERT(pos != std::string::npos); @@ -222,11 +265,12 @@ void ImportPathManager::AddImplicitPackageImportToParseList(StringView packageDi srcPos_ = srcPos; ES2PANDA_ASSERT( IsAbsolute(packageDir.Mutf8())); // This should be an absolute path for 'AddToParseList' be able to resolve it. - AddToParseList({util::ImportFlags::IMPLICIT_PACKAGE_IMPORT, Language::Id::ETS, packageDir.Utf8(), - util::ImportPathManager::DUMMY_PATH}); + auto importMetadata = ImportMetadata {util::ImportFlags::IMPLICIT_PACKAGE_IMPORT, Language::Id::ETS, + packageDir.Utf8(), util::ImportPathManager::DUMMY_PATH}; + AddToParseList(importMetadata); } -void ImportPathManager::AddToParseList(const ImportMetadata importMetadata) +void ImportPathManager::AddToParseList(const ImportMetadata &importMetadata) { auto resolvedPath = importMetadata.resolvedSource; bool isDeclForDynamic = !IsAbsolute(std::string(resolvedPath)); // Avoiding interpreting dynamic-path as directory. @@ -307,14 +351,14 @@ StringView ImportPathManager::GetRealPath(StringView path) const return UString(realPath, allocator_).View(); } -std::string ImportPathManager::TryMatchDynamicPath(std::string_view fixedPath) const +std::string ImportPathManager::TryMatchDependencies(std::string_view fixedPath) const { // Probably, 'NormalizePath' should be moved to 'AppendExtensionOrIndexFileIfOmitted'. auto normalizedPath = ark::os::NormalizePath(std::string(fixedPath)); std::replace_if( normalizedPath.begin(), normalizedPath.end(), [&](auto &c) { return c == pathDelimiter_[0]; }, '/'); // NOTE(dkofanov): #23877. See also 'arktsconfig.cpp'. - if (arktsConfig_->DynamicPaths().find(normalizedPath) != arktsConfig_->DynamicPaths().cend()) { + if (arktsConfig_->Dependencies().find(normalizedPath) != arktsConfig_->Dependencies().cend()) { return normalizedPath; } return {}; @@ -342,7 +386,7 @@ ImportPathManager::ResolvedPathRes ImportPathManager::AppendExtensionOrIndexFile std::replace_if( fixedPath.begin(), fixedPath.end(), [&](auto &c) { return ((delim != c) && ((c == '\\') || (c == '/'))); }, delim); - if (auto resolvedDynamic = TryMatchDynamicPath(fixedPath); !resolvedDynamic.empty()) { + if (auto resolvedDynamic = TryMatchDependencies(fixedPath); !resolvedDynamic.empty()) { return {UString(resolvedDynamic, allocator_).View().Utf8(), true}; } @@ -416,22 +460,6 @@ util::StringView ImportPathManager::FormModuleNameSolelyByAbsolutePath(const uti return util::UString(name, allocator_).View(); } -template -static std::string TryFormDynamicModuleName(const DynamicPaths &dynPaths, const ModuleNameFormer &tryFormModuleName) -{ - for (auto const &[unitName, did] : dynPaths) { - if (did.DeclPath().empty()) { - // NOTE(dkofanov): related to #23698. Current assumption: if 'declPath' is absent, it is a pure-dynamic - // source, and, as soon it won't be parsed, no module should be created. - continue; - } - if (auto res = tryFormModuleName(unitName, did.DeclPath()); res) { - return res.value(); - } - } - return ""; -} - util::StringView ImportPathManager::FormModuleName(const util::Path &path, const lexer::SourcePosition &srcPos) { srcPos_ = srcPos; @@ -444,6 +472,10 @@ util::StringView ImportPathManager::FormModuleName(const util::Path &path) return FormModuleNameSolelyByAbsolutePath(path); } + if (!parseList_.empty() && parseList_[0].importData.IsExternalBinaryImport()) { + return util::UString(parseList_[0].importData.ohmUrl, allocator_).View(); + } + if (arktsConfig_->Package().empty() && !arktsConfig_->UseUrl()) { return path.GetFileName(); } @@ -460,13 +492,6 @@ util::StringView ImportPathManager::FormModuleName(const util::Path &path) return FormUnitName(unitName) + (relativePath.empty() || FormUnitName(unitName).empty() ? relativePath : ("." + relativePath)); }; - - for (auto const &[unitName, unitPath] : arktsConfig_->Entries()) { - if (unitPath == filePath) { - return util::UString(unitName, allocator_).View(); - } - } - if (auto res = tryFormModuleName(arktsConfig_->Package(), arktsConfig_->BaseUrl() + pathDelimiter_.data()); res) { return util::UString(res.value(), allocator_).View(); } @@ -483,9 +508,6 @@ util::StringView ImportPathManager::FormModuleName(const util::Path &path) return util::UString(res.value(), allocator_).View(); } } - if (auto dmn = TryFormDynamicModuleName(arktsConfig_->DynamicPaths(), tryFormModuleName); !dmn.empty()) { - return util::UString(dmn, allocator_).View(); - } // NOTE (hurton): as a last step, try resolving using the BaseUrl again without a path delimiter at the end if (auto res = tryFormModuleName(arktsConfig_->Package(), arktsConfig_->BaseUrl()); res) { return util::UString(res.value(), allocator_).View(); @@ -522,12 +544,6 @@ util::StringView ImportPathManager::FormRelativePath(const util::Path &path) return path.GetFileNameWithExtension(); } - for (auto const &[unitName, unitPath] : arktsConfig_->Entries()) { - if (unitPath == filePath) { - return util::UString(unitName, allocator_).View(); - } - } - if (auto res = tryFormRelativePath(arktsConfig_->BaseUrl(), arktsConfig_->Package()); res) { return util::UString(res.value(), allocator_).View(); } @@ -538,7 +554,7 @@ util::StringView ImportPathManager::FormRelativePath(const util::Path &path) } } - for (auto const &[unitName, unitPath] : arktsConfig_->DynamicPaths()) { + for (auto const &[unitName, unitPath] : arktsConfig_->Dependencies()) { if (auto res = tryFormRelativePath(unitName, unitName); res) { return util::UString(res.value(), allocator_).View(); } diff --git a/ets2panda/util/importPathManager.h b/ets2panda/util/importPathManager.h index 169960dff2..48026693ef 100644 --- a/ets2panda/util/importPathManager.h +++ b/ets2panda/util/importPathManager.h @@ -37,6 +37,8 @@ enum class ImportFlags { NONE = 0U, DEFAULT_IMPORT = 1U << 1U, IMPLICIT_PACKAGE_IMPORT = 1U << 2U, + EXTERNAL_BINARY_IMPORT = 1U << 3U, // means .abc file in "path" in "dependencies" + EXTERNAL_SOURCE_IMPORT = 1U << 4U // means .d.ets file in "path" in "dependencies" }; } // namespace ark::es2panda::util @@ -79,7 +81,8 @@ public: Language::Id lang {Language::Id::COUNT}; std::string_view resolvedSource {}; std::string_view declPath {}; - std::string_view ohmUrl {}; + std::string ohmUrl {}; + std::string declText {}; // NOLINTEND(misc-non-private-member-variables-in-classes) bool HasSpecifiedDeclPath() const @@ -92,6 +95,16 @@ public: return (importFlags & ImportFlags::IMPLICIT_PACKAGE_IMPORT) != 0; } + bool IsExternalBinaryImport() const + { + return (importFlags & ImportFlags::EXTERNAL_BINARY_IMPORT) != 0; + } + + bool IsExternalSourceImport() const + { + return (importFlags & ImportFlags::EXTERNAL_SOURCE_IMPORT) != 0; + } + bool IsValid() const; }; @@ -140,7 +153,7 @@ public: ir::StringLiteral *importPath); void AddImplicitPackageImportToParseList(StringView packageDir, const lexer::SourcePosition &srcPos); - // API version for resolving paths. Kept only for API compatibility. Doesn't support 'dynamicPath'. + // API version for resolving paths. Kept only for API compatibility. Doesn't support 'dependencies'. util::StringView ResolvePathAPI(StringView curModulePath, ir::StringLiteral *importPath) const; void MarkAsParsed(StringView path); @@ -156,18 +169,19 @@ private: // `resolvedPath` is a realpath - if static path was resolved. // NOLINTBEGIN(misc-non-private-member-variables-in-classes) std::string_view resolvedPath; - bool resolvedIsDynamic {false}; + bool resolvedIsExternalModule {false}; // NOLINTEND(misc-non-private-member-variables-in-classes) }; ResolvedPathRes ResolvePath(std::string_view curModulePath, ir::StringLiteral *importPath) const; ResolvedPathRes ResolveAbsolutePath(const ir::StringLiteral &importPathNode) const; std::string_view DirOrDirWithIndexFile(StringView dir) const; ResolvedPathRes AppendExtensionOrIndexFileIfOmitted(StringView basePath) const; - std::string TryMatchDynamicPath(std::string_view fixedPath) const; + std::string TryMatchDependencies(std::string_view fixedPath) const; StringView GetRealPath(StringView path) const; + void ProcessExternalModuleImport(ImportMetadata &importData); public: - void AddToParseList(ImportMetadata importMetadata); + void AddToParseList(const ImportMetadata &importMetadata); #ifdef USE_UNIX_SYSCALL void UnixWalkThroughDirectoryAndAddToParseList(ImportMetadata importMetadata); #endif diff --git a/ets2panda/util/language.h b/ets2panda/util/language.h index aeeaf47177..e7604963e5 100644 --- a/ets2panda/util/language.h +++ b/ets2panda/util/language.h @@ -77,6 +77,17 @@ public: ES2PANDA_UNREACHABLE(); } + bool IsValid() const + { + for (auto [id, _, isDynamic] : ID_TABLE) { + if (id_ == id) { + return true; + } + } + + return false; + } + bool operator==(const Language &l) const { return id_ == l.id_; diff --git a/ets2panda/util/options.cpp b/ets2panda/util/options.cpp index 9f42bc27ab..680847e510 100644 --- a/ets2panda/util/options.cpp +++ b/ets2panda/util/options.cpp @@ -392,15 +392,12 @@ bool Options::ProcessEtsSpecificOptions() std::optional Options::ParseArktsConfig() { auto config = ArkTsConfig {GetArktsconfig(), diagnosticEngine_}; - std::unordered_set parsedConfigPath; - if (!config.Parse(parsedConfigPath)) { + if (!config.Parse()) { diagnosticEngine_.LogDiagnostic(diagnostic::INVALID_ARKTSCONFIG, util::DiagnosticMessageParams {util::StringView(GetArktsconfig())}); return std::nullopt; } config.ResolveAllDependenciesInArkTsConfig(); - // Don't need dependencies anymore, since all necessary information have been moved to current config - config.ResetDependencies(); return std::make_optional(config); } diff --git a/ets2panda/util/options.yaml b/ets2panda/util/options.yaml index c017d1347e..fb662ff9f4 100644 --- a/ets2panda/util/options.yaml +++ b/ets2panda/util/options.yaml @@ -95,11 +95,6 @@ options: default: false description: Dump debug info -- name: with-export-table - type: bool - default: false - description: enable abc file with export table info - - name: opt-level type: int default: 0 @@ -183,6 +178,11 @@ options: default: "" description: Output path for generated static declaration files +- name: emit-declaration + type: bool + default: false + description: Emit declaration to .abc file + - name: thread type: int default: 0 -- Gitee