From 5ee28101a3c3f28f8fc7193fb1aa9948895342df Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Tue, 17 Feb 2026 10:13:26 +0000 Subject: [PATCH] added first deps implementation --- .gitignore | 2 + .../gradle.java-common-conventions.gradle.kts | 3 + gradle/libs.versions.toml | 5 + .../prometeu-language-pbs/Cargo.toml | 9 - .../src/language_spec.rs | 16 -- .../prometeu-language-pbs/src/lib.rs | 3 - .../prometeu-languages-registry/Cargo.toml | 11 -- .../src/language_spec_registry.rs | 20 --- .../prometeu-languages-registry/src/lib.rs | 3 - .../prometeu-build-pipeline/Cargo.toml | 24 --- .../prometeu-build-pipeline/src/cli.rs | 158 ------------------ .../prometeu-build-pipeline/src/config.rs | 23 --- .../prometeu-build-pipeline/src/ctx.rs | 71 -------- .../src/emit_artifacts.rs | 17 -- .../prometeu-build-pipeline/src/lib.rs | 12 -- .../prometeu-build-pipeline/src/main.rs | 7 - .../src/phases/boot.rs | 12 -- .../src/phases/emit.rs | 7 - .../src/phases/language.rs | 11 -- .../src/phases/load_source.rs | 117 ------------- .../src/phases/lowering.rs | 6 - .../prometeu-build-pipeline/src/phases/mod.rs | 5 - .../prometeu-build-pipeline/src/pipeline.rs | 59 ------- old-compiler/prometeu-core/Cargo.toml | 10 -- old-compiler/prometeu-core/src/lib.rs | 3 - .../prometeu-core/src/source/diagnostics.rs | 81 --------- .../prometeu-core/src/source/file_db.rs | 69 -------- old-compiler/prometeu-core/src/source/ids.rs | 60 ------- .../prometeu-core/src/source/line_index.rs | 41 ----- old-compiler/prometeu-core/src/source/mod.rs | 13 -- .../prometeu-core/src/source/name_interner.rs | 56 ------- old-compiler/prometeu-core/src/source/span.rs | 39 ----- .../tests/source/file_db_line_index.rs | 69 -------- .../prometeu-core/tests/source/span_tests.rs | 14 -- old-compiler/prometeu-deps/Cargo.toml | 19 --- old-compiler/prometeu-deps/src/lib.rs | 19 --- .../prometeu-deps/src/load_sources.rs | 97 ----------- .../prometeu-deps/src/model/build_stack.rs | 6 - .../prometeu-deps/src/model/cache_blobs.rs | 7 - .../prometeu-deps/src/model/cache_plan.rs | 4 - .../prometeu-deps/src/model/deps_config.rs | 7 - .../prometeu-deps/src/model/loaded_file.rs | 5 - .../prometeu-deps/src/model/loaded_sources.rs | 8 - .../prometeu-deps/src/model/manifest.rs | 75 --------- old-compiler/prometeu-deps/src/model/mod.rs | 11 -- .../src/model/project_descriptor.rs | 14 -- .../src/model/project_sources.rs | 8 - .../prometeu-deps/src/model/resolved_graph.rs | 16 -- .../src/model/resolved_project.rs | 9 - .../prometeu-deps/src/workspace/host.rs | 32 ---- .../prometeu-deps/src/workspace/mod.rs | 6 - .../prometeu-deps/src/workspace/model.rs | 31 ---- .../src/workspace/phases/discover.rs | 131 --------------- .../src/workspace/phases/localize.rs | 62 ------- .../src/workspace/phases/materialize.rs | 144 ---------------- .../prometeu-deps/src/workspace/phases/mod.rs | 10 -- .../src/workspace/phases/policy.rs | 17 -- .../src/workspace/phases/run_all.rs | 50 ------ .../src/workspace/phases/stack.rs | 97 ----------- .../src/workspace/phases/state.rs | 58 ------- .../src/workspace/phases/validate.rs | 108 ------------ .../src/workspace/resolve_workspace.rs | 10 -- old-compiler/prometeu-language-api/Cargo.toml | 10 -- .../src/language_spec.rs | 21 --- old-compiler/prometeu-language-api/src/lib.rs | 3 - old-compiler/prometeu-lowering/Cargo.toml | 19 --- old-compiler/prometeu-lowering/src/lib.rs | 0 .../prometeu-frontend-pbs/build.gradle.kts | 9 + .../p/studio/compiler/PBSDefinitions.java | 13 ++ .../build.gradle.kts | 0 .../prometeu-compiler-core/build.gradle.kts | 7 + .../p/studio/compiler/model/FrontendSpec.java | 13 ++ .../java/p/studio/compiler/source/Span.java | 34 ++++ .../source/diagnostics/Diagnostic.java | 29 ++++ .../source/diagnostics/DiagnosticBundle.java | 4 + .../source/diagnostics/RelatedSpan.java | 15 ++ .../compiler/source/diagnostics/Severity.java | 11 ++ .../identifiers/AbstractSourceIdentifier.java | 24 +++ .../compiler/source/identifiers/FileId.java | 17 ++ .../compiler/source/identifiers/ModuleId.java | 7 + .../compiler/source/identifiers/NameId.java | 7 + .../compiler/source/identifiers/NodeId.java | 7 + .../source/identifiers/ProjectId.java | 11 ++ .../compiler/source/identifiers/SymbolId.java | 7 + .../compiler/source/identifiers/TypeId.java | 7 + .../prometeu-deps/build.gradle.kts | 10 ++ .../compiler/exceptions/BuildException.java | 11 ++ .../p/studio/compiler/model/BuildStack.java | 9 + .../studio/compiler/model/BuildingIssue.java | 11 ++ .../model/DependencyPipelineConfig.java | 10 ++ .../p/studio/compiler/model/LoadedFile.java | 4 + .../studio/compiler/model/LoadedSources.java | 17 ++ .../compiler/model/ProjectDescriptor.java | 21 +++ .../studio/compiler/model/ProjectSources.java | 9 + .../p/studio/compiler/model/PrometeuLock.java | 47 ++++++ .../compiler/model/PrometeuManifest.java | 88 ++++++++++ .../studio/compiler/model/ResolvedGraph.java | 15 ++ .../compiler/model/ResolvedWorkspace.java | 9 + .../p/studio/compiler/model/SourcePolicy.java | 6 + .../workspaces/DependencyPipelineContext.java | 71 ++++++++ .../workspaces/DependencyPipelinePhase.java | 8 + .../workspaces/DependencyPipelineService.java | 36 ++++ .../workspaces/DependencyReference.java | 6 + .../compiler/workspaces/ProjectInfo.java | 16 ++ .../compiler/workspaces/ProjectNode.java | 22 +++ .../workspaces/phases/DiscoverPhase.java | 94 +++++++++++ .../workspaces/phases/LocalizePhase.java | 33 ++++ .../workspaces/phases/MaterializePhase.java | 106 ++++++++++++ .../workspaces/phases/PolicyPhase.java | 18 ++ .../compiler/workspaces/phases/SeedPhase.java | 29 ++++ .../workspaces/phases/StackPhase.java | 61 +++++++ .../workspaces/phases/ValidatePhase.java | 30 ++++ .../DependencyPipelineServiceTest.java | 77 +++++++++ .../workspaces/DiscoverPhaseTest.java | 54 ++++++ .../workspaces/LocalizePhaseTest.java | 54 ++++++ .../workspaces/MaterializePhaseTest.java | 62 +++++++ .../compiler/workspaces/SeedPhaseTest.java | 27 +++ .../compiler/workspaces/StackPhaseTest.java | 57 +++++++ .../ValidateAndPolicyPhasesTest.java | 58 +++++++ .../prometeu-frontend-api/build.gradle.kts | 7 + .../compiler/FrontendRegistryService.java | 4 + .../build.gradle.kts | 10 ++ .../compiler/FrontendRegistryService.java | 30 ++++ prometeu-infra/build.gradle.kts | 2 + .../structures/ReadOnlyCollection.java | 89 ++++++++++ .../utilities/structures/ReadOnlyList.java | 86 ++++++++++ .../utilities/structures/ReadOnlySet.java | 36 ++++ .../java/p/studio/app/MessageUtilsTest.java | 14 -- settings.gradle.kts | 11 +- 129 files changed, 1691 insertions(+), 2176 deletions(-) delete mode 100644 old-compiler/languages/prometeu-language-pbs/Cargo.toml delete mode 100644 old-compiler/languages/prometeu-language-pbs/src/language_spec.rs delete mode 100644 old-compiler/languages/prometeu-language-pbs/src/lib.rs delete mode 100644 old-compiler/languages/prometeu-languages-registry/Cargo.toml delete mode 100644 old-compiler/languages/prometeu-languages-registry/src/language_spec_registry.rs delete mode 100644 old-compiler/languages/prometeu-languages-registry/src/lib.rs delete mode 100644 old-compiler/prometeu-build-pipeline/Cargo.toml delete mode 100644 old-compiler/prometeu-build-pipeline/src/cli.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/config.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/ctx.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/emit_artifacts.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/lib.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/main.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/phases/boot.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/phases/emit.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/phases/language.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/phases/load_source.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/phases/lowering.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/phases/mod.rs delete mode 100644 old-compiler/prometeu-build-pipeline/src/pipeline.rs delete mode 100644 old-compiler/prometeu-core/Cargo.toml delete mode 100644 old-compiler/prometeu-core/src/lib.rs delete mode 100644 old-compiler/prometeu-core/src/source/diagnostics.rs delete mode 100644 old-compiler/prometeu-core/src/source/file_db.rs delete mode 100644 old-compiler/prometeu-core/src/source/ids.rs delete mode 100644 old-compiler/prometeu-core/src/source/line_index.rs delete mode 100644 old-compiler/prometeu-core/src/source/mod.rs delete mode 100644 old-compiler/prometeu-core/src/source/name_interner.rs delete mode 100644 old-compiler/prometeu-core/src/source/span.rs delete mode 100644 old-compiler/prometeu-core/tests/source/file_db_line_index.rs delete mode 100644 old-compiler/prometeu-core/tests/source/span_tests.rs delete mode 100644 old-compiler/prometeu-deps/Cargo.toml delete mode 100644 old-compiler/prometeu-deps/src/lib.rs delete mode 100644 old-compiler/prometeu-deps/src/load_sources.rs delete mode 100644 old-compiler/prometeu-deps/src/model/build_stack.rs delete mode 100644 old-compiler/prometeu-deps/src/model/cache_blobs.rs delete mode 100644 old-compiler/prometeu-deps/src/model/cache_plan.rs delete mode 100644 old-compiler/prometeu-deps/src/model/deps_config.rs delete mode 100644 old-compiler/prometeu-deps/src/model/loaded_file.rs delete mode 100644 old-compiler/prometeu-deps/src/model/loaded_sources.rs delete mode 100644 old-compiler/prometeu-deps/src/model/manifest.rs delete mode 100644 old-compiler/prometeu-deps/src/model/mod.rs delete mode 100644 old-compiler/prometeu-deps/src/model/project_descriptor.rs delete mode 100644 old-compiler/prometeu-deps/src/model/project_sources.rs delete mode 100644 old-compiler/prometeu-deps/src/model/resolved_graph.rs delete mode 100644 old-compiler/prometeu-deps/src/model/resolved_project.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/host.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/mod.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/model.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/phases/discover.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/phases/localize.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/phases/materialize.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/phases/mod.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/phases/policy.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/phases/run_all.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/phases/stack.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/phases/state.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/phases/validate.rs delete mode 100644 old-compiler/prometeu-deps/src/workspace/resolve_workspace.rs delete mode 100644 old-compiler/prometeu-language-api/Cargo.toml delete mode 100644 old-compiler/prometeu-language-api/src/language_spec.rs delete mode 100644 old-compiler/prometeu-language-api/src/lib.rs delete mode 100644 old-compiler/prometeu-lowering/Cargo.toml delete mode 100644 old-compiler/prometeu-lowering/src/lib.rs create mode 100644 prometeu-compiler/frontends/prometeu-frontend-pbs/build.gradle.kts create mode 100644 prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSDefinitions.java rename prometeu-compiler/{ => prometeu-build-pipeline}/build.gradle.kts (100%) create mode 100644 prometeu-compiler/prometeu-compiler-core/build.gradle.kts create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/model/FrontendSpec.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/Span.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/Diagnostic.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/DiagnosticBundle.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/RelatedSpan.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/Severity.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/AbstractSourceIdentifier.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/FileId.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/ModuleId.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/NameId.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/NodeId.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/ProjectId.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/SymbolId.java create mode 100644 prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/TypeId.java create mode 100644 prometeu-compiler/prometeu-deps/build.gradle.kts create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/exceptions/BuildException.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/BuildStack.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/BuildingIssue.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/DependencyPipelineConfig.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/LoadedFile.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/LoadedSources.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ProjectDescriptor.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ProjectSources.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/PrometeuLock.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/PrometeuManifest.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ResolvedGraph.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ResolvedWorkspace.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/SourcePolicy.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelineContext.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelinePhase.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelineService.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyReference.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/ProjectInfo.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/ProjectNode.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/DiscoverPhase.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/LocalizePhase.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/MaterializePhase.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/PolicyPhase.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/SeedPhase.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/StackPhase.java create mode 100644 prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/ValidatePhase.java create mode 100644 prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/DependencyPipelineServiceTest.java create mode 100644 prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/DiscoverPhaseTest.java create mode 100644 prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/LocalizePhaseTest.java create mode 100644 prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/MaterializePhaseTest.java create mode 100644 prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/SeedPhaseTest.java create mode 100644 prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/StackPhaseTest.java create mode 100644 prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/ValidateAndPolicyPhasesTest.java create mode 100644 prometeu-compiler/prometeu-frontend-api/build.gradle.kts create mode 100644 prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/FrontendRegistryService.java create mode 100644 prometeu-compiler/prometeu-frontend-registry/build.gradle.kts create mode 100644 prometeu-compiler/prometeu-frontend-registry/src/main/java/p/studio/compiler/FrontendRegistryService.java create mode 100644 prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlyCollection.java create mode 100644 prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlyList.java create mode 100644 prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlySet.java delete mode 100644 prometeu-studio/src/test/java/p/studio/app/MessageUtilsTest.java diff --git a/.gitignore b/.gitignore index f81771b4..c13001d4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ build # Ignore Kotlin plugin data .kotlin + +.DS_Store diff --git a/buildSrc/src/main/kotlin/gradle.java-common-conventions.gradle.kts b/buildSrc/src/main/kotlin/gradle.java-common-conventions.gradle.kts index f2f60c15..669fae76 100644 --- a/buildSrc/src/main/kotlin/gradle.java-common-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/gradle.java-common-conventions.gradle.kts @@ -17,6 +17,9 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter:5.12.1") testRuntimeOnly("org.junit.platform:junit-platform-launcher") + + implementation("org.slf4j:slf4j-api:2.0.7") + implementation("org.slf4j:slf4j-simple:2.0.7") } java { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d6d65fa5..7b632744 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,11 +1,16 @@ [versions] javafx = "23.0.2" richtextfx = "0.11.2" +jackson = "2.18.2" [libraries] javafx-controls = { group = "org.openjfx", name = "javafx-controls", version.ref = "javafx" } javafx-fxml = { group = "org.openjfx", name = "javafx-fxml", version.ref = "javafx" } richtextfx = { group = "org.fxmisc.richtext", name = "richtextfx", version.ref = "richtextfx" } +jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" } +apache-commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = "3.13.0" } +apache-commons-io = { group = "commons-io", name = "commons-io", version = "2.13.0" } +apache-commons-collections = { group = "org.apache.commons", name = "commons-collections4", version = "4.4" } [plugins] javafx = { id = "org.openjfx.javafxplugin", version = "0.1.0" } diff --git a/old-compiler/languages/prometeu-language-pbs/Cargo.toml b/old-compiler/languages/prometeu-language-pbs/Cargo.toml deleted file mode 100644 index d09a2da5..00000000 --- a/old-compiler/languages/prometeu-language-pbs/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "prometeu-language-pbs" -version = "0.1.0" -edition = "2021" -license = "MIT" -description = "" - -[dependencies] -prometeu-language-api = { path = "../../prometeu-language-api" } \ No newline at end of file diff --git a/old-compiler/languages/prometeu-language-pbs/src/language_spec.rs b/old-compiler/languages/prometeu-language-pbs/src/language_spec.rs deleted file mode 100644 index 82b20ca0..00000000 --- a/old-compiler/languages/prometeu-language-pbs/src/language_spec.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::sync::OnceLock; -use prometeu_language_api::{LanguageSpec, SourcePolicy}; - -pub static LANGUAGE_SPEC: OnceLock = OnceLock::new(); - -fn registry() -> &'static LanguageSpec { - LANGUAGE_SPEC.get_or_init(|| { - LanguageSpec { - id: "pbs", - source_policy: SourcePolicy { - extensions: vec!["pbs"], - case_sensitive: true, - }, - } - }) -} \ No newline at end of file diff --git a/old-compiler/languages/prometeu-language-pbs/src/lib.rs b/old-compiler/languages/prometeu-language-pbs/src/lib.rs deleted file mode 100644 index 046a7b10..00000000 --- a/old-compiler/languages/prometeu-language-pbs/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod language_spec; - -pub use language_spec::LANGUAGE_SPEC; \ No newline at end of file diff --git a/old-compiler/languages/prometeu-languages-registry/Cargo.toml b/old-compiler/languages/prometeu-languages-registry/Cargo.toml deleted file mode 100644 index 8950c14d..00000000 --- a/old-compiler/languages/prometeu-languages-registry/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "prometeu-languages-registry" -version = "0.1.0" -edition = "2021" -license = "MIT" -description = "" - -[dependencies] -prometeu-language-api = { path = "../../prometeu-language-api" } - -prometeu-language-pbs = { path = "../prometeu-language-pbs" } \ No newline at end of file diff --git a/old-compiler/languages/prometeu-languages-registry/src/language_spec_registry.rs b/old-compiler/languages/prometeu-languages-registry/src/language_spec_registry.rs deleted file mode 100644 index 98e7569d..00000000 --- a/old-compiler/languages/prometeu-languages-registry/src/language_spec_registry.rs +++ /dev/null @@ -1,20 +0,0 @@ -use prometeu_language_api::LanguageSpec; -use std::collections::HashMap; -use std::sync::OnceLock; - -use prometeu_language_pbs::LANGUAGE_SPEC as PBS_LANGUAGE_SPEC; - -static REGISTRY: OnceLock> = OnceLock::new(); - -fn registry() -> &'static HashMap<&'static str, LanguageSpec> { - let pbs = PBS_LANGUAGE_SPEC.get().unwrap(); - REGISTRY.get_or_init(|| { - HashMap::from([ - (pbs.id, pbs.clone()), - ]) - }) -} - -pub fn get_language_spec(id: &str) -> Option<&LanguageSpec> { - registry().get(id) -} diff --git a/old-compiler/languages/prometeu-languages-registry/src/lib.rs b/old-compiler/languages/prometeu-languages-registry/src/lib.rs deleted file mode 100644 index f9cca34d..00000000 --- a/old-compiler/languages/prometeu-languages-registry/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod language_spec_registry; - -pub use language_spec_registry::get_language_spec; \ No newline at end of file diff --git a/old-compiler/prometeu-build-pipeline/Cargo.toml b/old-compiler/prometeu-build-pipeline/Cargo.toml deleted file mode 100644 index d2beffa2..00000000 --- a/old-compiler/prometeu-build-pipeline/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "prometeu-build-pipeline" -version = "0.1.0" -edition = "2021" -license.workspace = true -repository.workspace = true - -[[bin]] -name = "prometeu-build-pipeline" -path = "src/main.rs" - -[package.metadata.dist] -dist = true -include = ["../../VERSION.txt"] - -[dependencies] -prometeu-deps = { path = "../prometeu-deps" } -prometeu-core = { path = "../prometeu-core" } -prometeu-languages-registry = { path = "../languages/prometeu-languages-registry" } -clap = { version = "4.5.54", features = ["derive"] } -serde = { version = "1.0.228", features = ["derive"] } -serde_json = "1.0.149" -anyhow = "1.0.100" -camino = "1.2.2" diff --git a/old-compiler/prometeu-build-pipeline/src/cli.rs b/old-compiler/prometeu-build-pipeline/src/cli.rs deleted file mode 100644 index 397fb7bb..00000000 --- a/old-compiler/prometeu-build-pipeline/src/cli.rs +++ /dev/null @@ -1,158 +0,0 @@ -use crate::pipeline::run_phases; -use crate::{BuildMode, PipelineConfig, PipelineInput, PipelineOutput}; -use anyhow::{Context, Result}; -use clap::{Parser, Subcommand}; -use prometeu_deps::{load_sources, resolve_workspace, DepsConfig}; -use std::path::{Path, PathBuf}; -use camino::Utf8Path; -use crate::emit_artifacts::{emit_artifacts, EmitOptions}; - -/// Command line interface for the Prometeu Compiler. -#[derive(Parser)] -#[command(name = "prometeu")] -#[command(version, about = "PROMETEU toolchain entrypoint", long_about = None)] -pub struct Cli { - #[command(subcommand)] - pub command: Commands, -} - -/// Available subcommands for the compiler. -#[derive(Subcommand)] -pub enum Commands { - /// Builds a Prometeu project by compiling source code into an artifact (pbc/program image). - Build { - /// Path to the project root directory. - project_dir: PathBuf, - - /// Path to save the compiled artifact. - /// If omitted, deps/pipeline decide a default under target/ or dist/. - #[arg(short, long)] - out: Option, - - /// Whether to generate a .json symbols file for source mapping. - #[arg(long, default_value_t = true)] - emit_symbols: bool, - - /// Whether to generate a .disasm file for debugging. - #[arg(long, default_value_t = true)] - emit_disasm: bool, - - /// Whether to explain the dependency resolution process. - #[arg(long)] - explain_deps: bool, - - /// Build mode (debug/release). - #[arg(long, default_value = "debug")] - mode: String, - }, - - /// Verifies if a Prometeu project is valid without emitting code. - Verify { - project_dir: PathBuf, - - /// Whether to explain the dependency resolution process. - #[arg(long)] - explain_deps: bool, - }, -} - -pub fn run() -> Result<()> { - let cli = Cli::parse(); - - match cli.command { - Commands::Build { - project_dir, - out, - emit_disasm, - emit_symbols, - explain_deps, - mode, - } => { - let build_mode = parse_mode(&mode)?; - let cfg = PipelineConfig { - mode: build_mode, - enable_cache: true, - enable_frontends: false, - }; - - let pipeline_output = run_pipeline(cfg, &project_dir, explain_deps) - .context("pipeline: failed to execute pipeline")?; - - for diagnostics in &pipeline_output.diagnostics { - eprintln!("{:?}", diagnostics); - } - - let emit_opts = EmitOptions { - out, - emit_symbols, - emit_disasm, - }; - - emit_artifacts(&emit_opts, &pipeline_output) - .context("emit: failed to write artifacts")?; - - if pipeline_output.diagnostics.iter().any(|d| d.severity.is_error()) { - anyhow::bail!("build failed due to errors"); - } - } - - Commands::Verify { - project_dir, - explain_deps, - } => { - let cfg = PipelineConfig { - mode: BuildMode::Test, - enable_cache: true, - enable_frontends: false, - }; - - let pipeline_output = run_pipeline(cfg, &project_dir, explain_deps) - .context("pipeline: failed to execute pipeline")?; - - for diagnostic in &pipeline_output.diagnostics { - eprintln!("{:?}", diagnostic); - } - - if pipeline_output.diagnostics.iter().any(|d| d.severity.is_error()) { - anyhow::bail!("verify failed due to errors"); - } - } - } - - Ok(()) -} - - -fn run_pipeline(cfg: PipelineConfig, project_dir: &Path, explain_deps: bool) -> Result { - let deps_cfg = DepsConfig { - explain: explain_deps, - cache_dir: Default::default(), - registry_dirs: vec![], - }; - - let project_dir_path_buf = Utf8Path::from_path(project_dir) - .with_context(|| format!("deps: failed to convert project_dir to Utf8Path: {:?}", project_dir))?; - let resolved = resolve_workspace(&deps_cfg, project_dir_path_buf) - .with_context(|| format!("deps: failed to resolve project at {:?}", project_dir))?; - - let sources = load_sources(&deps_cfg, &resolved) - .context("deps: failed to load sources")?; - - let input = PipelineInput { - graph: resolved.graph, - stack: resolved.stack, - sources - }; - - Ok(run_phases(cfg, input)) -} - -/// Parse `--mode` from CLI. -fn parse_mode(s: &str) -> Result { - match s.to_ascii_lowercase().as_str() { - "debug" => Ok(BuildMode::Debug), - "release" => Ok(BuildMode::Release), - "test" => Ok(BuildMode::Test), - other => anyhow::bail!("invalid --mode '{}': expected debug|release|test", other), - } -} diff --git a/old-compiler/prometeu-build-pipeline/src/config.rs b/old-compiler/prometeu-build-pipeline/src/config.rs deleted file mode 100644 index 8cf9b38c..00000000 --- a/old-compiler/prometeu-build-pipeline/src/config.rs +++ /dev/null @@ -1,23 +0,0 @@ -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum BuildMode { - Debug, - Release, - Test, -} - -#[derive(Debug, Clone)] -pub struct PipelineConfig { - pub mode: BuildMode, - pub enable_cache: bool, - pub enable_frontends: bool, -} - -impl Default for PipelineConfig { - fn default() -> Self { - Self { - mode: BuildMode::Debug, - enable_cache: true, - enable_frontends: false, // Hard Reset default: pipeline runs with no FE. - } - } -} diff --git a/old-compiler/prometeu-build-pipeline/src/ctx.rs b/old-compiler/prometeu-build-pipeline/src/ctx.rs deleted file mode 100644 index 7e4097ec..00000000 --- a/old-compiler/prometeu-build-pipeline/src/ctx.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::any::Any; -use prometeu_core::{Diagnostic, FileDB, FileId, NameInterner, ProjectId}; -use prometeu_deps::BuildStack; - -/// Per-project arena slot created from the BuildStack order. -/// The pipeline owns this vector and indexes it by stack position. -#[derive(Debug)] -pub struct ProjectCtx { - pub project_id: ProjectId, - - /// FileIds inserted into `source_db` for this project. - pub files: Vec, - - /// Frontend output (TypedHIRBundle or similar) - intentionally opaque. - pub frontend_out: Option>, - - /// Backend output (ProgramImage / BytecodeModule / Artifact). - /// Keep as opaque until you finalize your bytecode/image crate. - pub backend_out: Option>, -} - -impl ProjectCtx { - pub fn new(project_id: ProjectId) -> Self { - Self { - project_id, - files: Vec::new(), - frontend_out: None, - backend_out: None, - } - } -} - -#[derive(Debug)] -pub struct PipelineCtx { - pub source_db: FileDB, - pub interner: NameInterner, - pub diagnostics: Vec, - pub projects: Vec, -} - -impl PipelineCtx { - pub fn new() -> Self { - Self { - source_db: FileDB::new(), - interner: NameInterner::new(), - diagnostics: Vec::new(), - projects: Vec::new(), - } - } - - pub fn push_diagnostic(&mut self, d: Diagnostic) { - self.diagnostics.push(d); - } - - /// Initialize per-project contexts from the BuildStack order. - pub fn init_projects_from_stack(&mut self, stack: &BuildStack) { - self.projects.clear(); - self.projects.reserve(stack.projects.len()); - for project_id in &stack.projects { - self.projects.push(ProjectCtx::new(project_id.clone())); - } - } - - pub fn project_ctx_mut(&mut self, index_in_stack: usize) -> &mut ProjectCtx { - &mut self.projects[index_in_stack] - } - - pub fn project_ctx(&self, index_in_stack: usize) -> &ProjectCtx { - &self.projects[index_in_stack] - } -} diff --git a/old-compiler/prometeu-build-pipeline/src/emit_artifacts.rs b/old-compiler/prometeu-build-pipeline/src/emit_artifacts.rs deleted file mode 100644 index ce6f601f..00000000 --- a/old-compiler/prometeu-build-pipeline/src/emit_artifacts.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::path::PathBuf; -use crate::PipelineOutput; - -pub struct EmitOptions { - pub(crate) out: Option, - pub(crate) emit_symbols: bool, - pub(crate) emit_disasm: bool, -} - -pub fn emit_artifacts(_opts: &EmitOptions, _outp: &PipelineOutput) -> anyhow::Result<()> { - // Later: - // - decide output dir (opts.out or default) - // - write .pbc / program image - // - write symbols.json (if exists) - // - write disasm (if exists) - Ok(()) -} \ No newline at end of file diff --git a/old-compiler/prometeu-build-pipeline/src/lib.rs b/old-compiler/prometeu-build-pipeline/src/lib.rs deleted file mode 100644 index 9f0cb56b..00000000 --- a/old-compiler/prometeu-build-pipeline/src/lib.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub mod cli; -pub mod config; -pub mod ctx; -pub mod pipeline; -pub mod phases; -mod emit_artifacts; - -pub use config::*; -pub use ctx::*; -pub use pipeline::*; -pub use cli::run; - diff --git a/old-compiler/prometeu-build-pipeline/src/main.rs b/old-compiler/prometeu-build-pipeline/src/main.rs deleted file mode 100644 index b8db3c41..00000000 --- a/old-compiler/prometeu-build-pipeline/src/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -use anyhow::Result; - -/// Main entry point for the Prometeu Compiler binary. -/// It delegates execution to the library's `run` function. -fn main() -> Result<()> { - prometeu_build_pipeline::run() -} diff --git a/old-compiler/prometeu-build-pipeline/src/phases/boot.rs b/old-compiler/prometeu-build-pipeline/src/phases/boot.rs deleted file mode 100644 index fbb0a164..00000000 --- a/old-compiler/prometeu-build-pipeline/src/phases/boot.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::{ - config::PipelineConfig, - ctx::PipelineCtx, - pipeline::{PipelineInput}, -}; - -pub fn run(_cfg: &PipelineConfig, input: &PipelineInput, ctx: &mut PipelineCtx) { - // Arena init: one ProjectCtx per project in stack order. - ctx.init_projects_from_stack(&input.stack); - - // NOTE: no filesystem, no FE/BE assumptions here. -} diff --git a/old-compiler/prometeu-build-pipeline/src/phases/emit.rs b/old-compiler/prometeu-build-pipeline/src/phases/emit.rs deleted file mode 100644 index 704f8298..00000000 --- a/old-compiler/prometeu-build-pipeline/src/phases/emit.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::{config::PipelineConfig, ctx::PipelineCtx, pipeline::{Artifacts, PipelineInput}}; - -pub fn run(_cfg: &PipelineConfig, _input: &PipelineInput, _ctx: &mut PipelineCtx) -> Artifacts { - // Hard Reset stub: - // - later: emit build outputs (to FS via deps if you want strict IO centralization). - Artifacts::default() -} diff --git a/old-compiler/prometeu-build-pipeline/src/phases/language.rs b/old-compiler/prometeu-build-pipeline/src/phases/language.rs deleted file mode 100644 index 06318e91..00000000 --- a/old-compiler/prometeu-build-pipeline/src/phases/language.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::{config::PipelineConfig, ctx::PipelineCtx, pipeline::PipelineInput}; - -pub fn run(cfg: &PipelineConfig, _input: &PipelineInput, _ctx: &mut PipelineCtx) { - if !cfg.enable_frontends { - return; - } - - // Hard Reset: - // - no FE wired yet. - // - later: iterate projects in stack order and call FE plugin(s). -} diff --git a/old-compiler/prometeu-build-pipeline/src/phases/load_source.rs b/old-compiler/prometeu-build-pipeline/src/phases/load_source.rs deleted file mode 100644 index 785abc07..00000000 --- a/old-compiler/prometeu-build-pipeline/src/phases/load_source.rs +++ /dev/null @@ -1,117 +0,0 @@ -use prometeu_core::{Diagnostic, Severity, Span}; -use prometeu_deps::LoadedSources; -use crate::{ - config::PipelineConfig, - ctx::PipelineCtx, - pipeline::PipelineInput, -}; - -pub fn run(_cfg: &PipelineConfig, input: &PipelineInput, ctx: &mut PipelineCtx) { - load_sources(&input.sources, ctx); - - for i in 0..ctx.projects.len() { - let is_empty = ctx.projects[i].files.is_empty(); - - if is_empty { - let project_id = &input.stack.projects[i]; - let project_name = input.graph.project(project_id).unwrap().name.clone(); - - ctx.push_diagnostic(Diagnostic { - severity: Severity::Warning, - code: "PIPELINE_NO_SOURCES".into(), - message: format!( - "Project '{}' has no source files loaded.", - project_name - ), - span: Span::none(), - related: vec![], - }); - } - } -} - -fn load_sources(sources: &LoadedSources, ctx: &mut PipelineCtx) { - let stack_len = ctx.projects.len(); - let src_len = sources.per_project.len(); - - // 1) Diagnostic is sizes don't match - if src_len != stack_len { - ctx.push_diagnostic(Diagnostic { - severity: Severity::Error, - code: "PIPELINE_SOURCES_STACK_LEN_MISMATCH".into(), - message: format!( - "LoadedSources.per_project len ({}) does not match BuildStack len ({}).", - src_len, stack_len - ), - span: Span::none(), - related: vec![], - }); - } - - // 2) Process the bare minimum (don't panic, just keep running with diagnostics) - let n = stack_len.min(src_len); - - for i in 0..n { - let expected = ctx.projects[i].project_id; - let got = sources.per_project[i].project_id; - - if got != expected { - ctx.push_diagnostic(Diagnostic { - severity: Severity::Error, - code: "PIPELINE_SOURCES_STACK_ORDER_MISMATCH".into(), - message: format!( - "LoadedSources is not aligned with BuildStack at index {}: expected project_id {:?}, got {:?}.", - i, expected, got - ), - span: Span::none(), - related: vec![], - }); - - // there is no fix tolerance here, if it is wrong, it is wrong - // just catch as much diagnostics as possible before "crashing" - continue; - } - - for f in &sources.per_project[i].files { - let file_id = ctx.source_db.upsert(&f.uri, &f.text); - ctx.projects[i].files.push(file_id); - } - } - - // 3) If any LoadSources remains, it is a deps bug - if src_len > stack_len { - for extra in &sources.per_project[stack_len..] { - ctx.push_diagnostic(Diagnostic { - severity: Severity::Error, - code: "PIPELINE_SOURCES_EXTRA_PROJECT".into(), - message: format!( - "LoadedSources contains extra project_id {:?} not present in BuildStack.", - extra.project_id - ), - span: Span::none(), - related: vec![], - }); - } - } - - // 4) If missing inputs, it is another deps bug... - if stack_len > src_len { - let mut diagnostics: Vec = Vec::new(); - for missing in &ctx.projects[src_len..] { - diagnostics.push(Diagnostic { - severity: Severity::Error, - code: "PIPELINE_SOURCES_MISSING_PROJECT".into(), - message: format!( - "LoadedSources missing sources for project_id {:?} present in BuildStack.", - missing.project_id - ), - span: Span::none(), - related: vec![], - }); - } - for diagnostic in diagnostics { - ctx.push_diagnostic(diagnostic); - } - } -} - diff --git a/old-compiler/prometeu-build-pipeline/src/phases/lowering.rs b/old-compiler/prometeu-build-pipeline/src/phases/lowering.rs deleted file mode 100644 index 305cc8f1..00000000 --- a/old-compiler/prometeu-build-pipeline/src/phases/lowering.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::{config::PipelineConfig, ctx::PipelineCtx, pipeline::PipelineInput}; - -pub fn run(_cfg: &PipelineConfig, _input: &PipelineInput, _ctx: &mut PipelineCtx) { - // Hard Reset stub: - // - later: consume TypedHIRBundle(s) and lower into ProgramImage/BytecodeModule. -} diff --git a/old-compiler/prometeu-build-pipeline/src/phases/mod.rs b/old-compiler/prometeu-build-pipeline/src/phases/mod.rs deleted file mode 100644 index 25bb69e6..00000000 --- a/old-compiler/prometeu-build-pipeline/src/phases/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod boot; -pub mod load_source; -pub mod language; -pub mod lowering; -pub mod emit; diff --git a/old-compiler/prometeu-build-pipeline/src/pipeline.rs b/old-compiler/prometeu-build-pipeline/src/pipeline.rs deleted file mode 100644 index b8c5d73a..00000000 --- a/old-compiler/prometeu-build-pipeline/src/pipeline.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::{config::PipelineConfig, ctx::PipelineCtx, phases}; -use prometeu_core::Diagnostic; -use prometeu_deps::{BuildStack, LoadedSources, ResolvedGraph}; - -#[derive(Debug, Clone)] -pub struct PipelineInput { - pub graph: ResolvedGraph, - pub stack: BuildStack, - pub sources: LoadedSources -} - -#[derive(Debug, Default, Clone)] -pub struct PipelineStats { - pub projects_count: usize, - pub files_count: usize, -} - -#[derive(Debug, Default, Clone)] -pub struct Artifacts { - // placeholder: later include produced ProgramImage(s), debug bundles, logs, etc. -} - -#[derive(Debug, Default)] -pub struct PipelineOutput { - pub diagnostics: Vec, - pub artifacts: Artifacts, - pub stats: PipelineStats, -} - -pub(crate) fn run_phases(cfg: PipelineConfig, input: PipelineInput) -> PipelineOutput { - let mut ctx = PipelineCtx::new(); - - // Boot: create project slots in arena order. - phases::boot::run(&cfg, &input, &mut ctx); - - // Load source: populate FileDB from LoadedSources. - phases::load_source::run(&cfg, &input, &mut ctx); - - // Frontend phase (stub / optional). - phases::language::run(&cfg, &input, &mut ctx); - - // Backend phase (stub). - phases::lowering::run(&cfg, &input, &mut ctx); - - // Emit phase (stub). - let artifacts = phases::emit::run(&cfg, &input, &mut ctx); - - // Stats (basic). - let mut stats = PipelineStats::default(); - stats.projects_count = ctx.projects.len(); - stats.files_count = ctx.projects.iter().map(|p| p.files.len()).sum(); - - PipelineOutput { - diagnostics: ctx.diagnostics, - artifacts, - stats, - } -} - diff --git a/old-compiler/prometeu-core/Cargo.toml b/old-compiler/prometeu-core/Cargo.toml deleted file mode 100644 index da0e0cf8..00000000 --- a/old-compiler/prometeu-core/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "prometeu-core" -version = "0.1.0" -edition = "2024" -license.workspace = true - -[dependencies] -serde = { version = "1.0.228", features = ["derive"] } -serde_json = "1.0.149" -prometeu-bytecode = { path = "../prometeu-bytecode" } diff --git a/old-compiler/prometeu-core/src/lib.rs b/old-compiler/prometeu-core/src/lib.rs deleted file mode 100644 index 07f283b9..00000000 --- a/old-compiler/prometeu-core/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod source; - -pub use source::*; \ No newline at end of file diff --git a/old-compiler/prometeu-core/src/source/diagnostics.rs b/old-compiler/prometeu-core/src/source/diagnostics.rs deleted file mode 100644 index bde61425..00000000 --- a/old-compiler/prometeu-core/src/source/diagnostics.rs +++ /dev/null @@ -1,81 +0,0 @@ -use serde::{Serialize, Serializer}; -use crate::Span; - -#[derive(Debug, Clone, PartialEq)] -pub enum Severity { - Error, - Warning, -} - -impl Severity { - pub fn is_error(&self) -> bool { - match self { - Severity::Error => true, - Severity::Warning => false, - } - } -} - -impl Serialize for Severity { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Severity::Error => serializer.serialize_str("error"), - Severity::Warning => serializer.serialize_str("warning"), - } - } -} - -#[derive(Debug, Clone, Serialize)] -pub struct Diagnostic { - pub severity: Severity, - pub code: String, - pub message: String, - pub span: Span, - pub related: Vec<(String, Span)>, -} - -#[derive(Debug, Clone, Serialize)] -pub struct DiagnosticBundle { - pub diagnostics: Vec, -} - -impl DiagnosticBundle { - pub fn new() -> Self { - Self { - diagnostics: Vec::new(), - } - } - - pub fn push(&mut self, diagnostic: Diagnostic) { - self.diagnostics.push(diagnostic); - } - - pub fn error(code: &str, message: String, span: Span) -> Self { - let mut bundle = Self::new(); - bundle.push(Diagnostic { - severity: Severity::Error, - code: code.to_string(), - message, - span, - related: Vec::new(), - }); - bundle - } - - pub fn has_errors(&self) -> bool { - self.diagnostics - .iter() - .any(|d| matches!(d.severity, Severity::Error)) - } -} - -impl From for DiagnosticBundle { - fn from(diagnostic: Diagnostic) -> Self { - let mut bundle = Self::new(); - bundle.push(diagnostic); - bundle - } -} diff --git a/old-compiler/prometeu-core/src/source/file_db.rs b/old-compiler/prometeu-core/src/source/file_db.rs deleted file mode 100644 index dbc9f698..00000000 --- a/old-compiler/prometeu-core/src/source/file_db.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::collections::HashMap; -use crate::FileId; -use crate::LineIndex; - -#[derive(Default, Debug)] -pub struct FileDB { - files: Vec, - uri_to_id: HashMap, -} - -#[derive(Debug)] -struct FileData { - uri: String, - text: String, - line_index: LineIndex, -} - -impl FileDB { - pub fn new() -> Self { - Self { - files: Vec::new(), - uri_to_id: HashMap::new(), - } - } - - pub fn upsert(&mut self, uri: &str, text: &str) -> FileId { - if let Some(&id) = self.uri_to_id.get(uri) { - let line_index = LineIndex::new(&text); - self.files[id.0 as usize] = FileData { - uri: uri.to_owned(), - text: text.to_owned(), - line_index, - }; - id - } else { - let id = FileId(self.files.len() as u32); - let line_index = LineIndex::new(&text); - self.files.push(FileData { - uri: uri.to_owned(), - text: text.to_owned(), - line_index, - }); - self.uri_to_id.insert(uri.to_string(), id); - id - } - } - - pub fn file_id(&self, uri: &str) -> Option { - self.uri_to_id.get(uri).copied() - } - - pub fn uri(&self, id: FileId) -> &str { - &self.files[id.0 as usize].uri - } - - pub fn text(&self, id: FileId) -> &str { - &self.files[id.0 as usize].text - } - - pub fn line_index(&self, id: FileId) -> &LineIndex { - &self.files[id.0 as usize].line_index - } - - /// Returns a list of all known file IDs in insertion order. - pub fn all_files(&self) -> Vec { - (0..self.files.len()).map(|i| FileId(i as u32)).collect() - } -} - diff --git a/old-compiler/prometeu-core/src/source/ids.rs b/old-compiler/prometeu-core/src/source/ids.rs deleted file mode 100644 index d7965e07..00000000 --- a/old-compiler/prometeu-core/src/source/ids.rs +++ /dev/null @@ -1,60 +0,0 @@ -macro_rules! define_id { - ($name:ident) => { - #[repr(transparent)] - #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, serde::Serialize, serde::Deserialize)] - pub struct $name(pub u32); - - impl $name { - pub const NONE: $name = $name(u32::MAX); - - #[inline] - pub const fn as_u32(self) -> u32 { self.0 } - - #[inline] - pub fn is_none(self) -> bool { - self == $name::NONE - } - } - - impl From for $name { - #[inline] - fn from(value: u32) -> Self { Self(value) } - } - - impl From<$name> for u32 { - #[inline] - fn from(value: $name) -> Self { value.0 } - } - }; -} - -define_id!(FileId); -define_id!(NodeId); -define_id!(NameId); -define_id!(SymbolId); -define_id!(TypeId); -define_id!(ModuleId); -define_id!(ProjectId); - -#[cfg(test)] -mod tests { - use super::*; - use std::collections::HashMap; - use std::mem::size_of; - - #[test] - fn ids_are_repr_transparent_and_hashable() { - assert_eq!(size_of::(), 4); - assert_eq!(size_of::(), 4); - assert_eq!(size_of::(), 4); - assert_eq!(size_of::(), 4); - assert_eq!(size_of::(), 4); - assert_eq!(size_of::(), 4); - assert_eq!(size_of::(), 4); - - // Hash/Eq usage - let mut m: HashMap = HashMap::new(); - m.insert(SymbolId(1), "one"); - assert_eq!(m.get(&SymbolId(1)).copied(), Some("one")); - } -} diff --git a/old-compiler/prometeu-core/src/source/line_index.rs b/old-compiler/prometeu-core/src/source/line_index.rs deleted file mode 100644 index 87d98dae..00000000 --- a/old-compiler/prometeu-core/src/source/line_index.rs +++ /dev/null @@ -1,41 +0,0 @@ -#[derive(Debug)] -pub struct LineIndex { - line_starts: Vec, - total_len: u32, -} - -impl LineIndex { - pub fn new(text: &str) -> Self { - let mut line_starts = vec![0]; - for (offset, c) in text.char_indices() { - if c == '\n' { - line_starts.push((offset + 1) as u32); - } - } - Self { - line_starts, - total_len: text.len() as u32, - } - } - - pub fn offset_to_line_col(&self, offset: u32) -> (u32, u32) { - let line = match self.line_starts.binary_search(&offset) { - Ok(line) => line as u32, - Err(line) => (line - 1) as u32, - }; - let col = offset - self.line_starts[line as usize]; - (line, col) - } - - pub fn line_col_to_offset(&self, line: u32, col: u32) -> Option { - let start = *self.line_starts.get(line as usize)?; - let offset = start + col; - - let next_start = self.line_starts.get(line as usize + 1).copied().unwrap_or(self.total_len); - if offset < next_start || (offset == next_start && offset == self.total_len) { - Some(offset) - } else { - None - } - } -} diff --git a/old-compiler/prometeu-core/src/source/mod.rs b/old-compiler/prometeu-core/src/source/mod.rs deleted file mode 100644 index 69551f4a..00000000 --- a/old-compiler/prometeu-core/src/source/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -mod ids; -mod span; -mod file_db; -mod name_interner; -mod diagnostics; -mod line_index; - -pub use ids::*; -pub use span::Span; -pub use file_db::FileDB; -pub use line_index::LineIndex; -pub use name_interner::NameInterner; -pub use diagnostics::*; \ No newline at end of file diff --git a/old-compiler/prometeu-core/src/source/name_interner.rs b/old-compiler/prometeu-core/src/source/name_interner.rs deleted file mode 100644 index 1381ee2a..00000000 --- a/old-compiler/prometeu-core/src/source/name_interner.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::collections::HashMap; -use crate::NameId; - -#[derive(Debug, Default, Clone)] -pub struct NameInterner { - names: Vec, - ids: HashMap, -} - -impl NameInterner { - pub fn new() -> Self { - Self { - names: Vec::new(), - ids: HashMap::new(), - } - } - - pub fn intern(&mut self, s: &str) -> NameId { - if let Some(id) = self.ids.get(s) { - return *id; - } - - let id = NameId(self.names.len() as u32); - self.names.push(s.to_string()); - self.ids.insert(self.names[id.0 as usize].clone(), id); - id - } - - pub fn get(&self, s: &str) -> Option { - self.ids.get(s).copied() - } - - pub fn resolve(&self, id: NameId) -> &str { - &self.names[id.0 as usize] - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn interner_intern_resolve_roundtrip() { - let mut interner = NameInterner::new(); - let id = interner.intern("foo"); - assert_eq!(interner.resolve(id), "foo"); - } - - #[test] - fn interner_dedups_strings() { - let mut interner = NameInterner::new(); - let id1 = interner.intern("bar"); - let id2 = interner.intern("bar"); - assert_eq!(id1, id2); - } -} \ No newline at end of file diff --git a/old-compiler/prometeu-core/src/source/span.rs b/old-compiler/prometeu-core/src/source/span.rs deleted file mode 100644 index 2bd17b7c..00000000 --- a/old-compiler/prometeu-core/src/source/span.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::FileId; - -#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct Span { - pub file: FileId, - pub start: u32, // byte offset - pub end: u32, // byte offset, exclusive -} - -impl Span { - #[inline] - pub fn new(file: FileId, start: u32, end: u32) -> Self { - Self { file, start, end } - } - - #[inline] - pub fn none() -> Self { - Self { - file: FileId::NONE, - start: 0, - end: 0, - } - } - - #[inline] - pub fn is_none(&self) -> bool { - self.file.is_none() - } - - #[inline] - pub fn len(&self) -> u32 { - self.end.saturating_sub(self.start) - } - - #[inline] - pub fn contains(&self, byte: u32) -> bool { - self.start <= byte && byte < self.end - } -} diff --git a/old-compiler/prometeu-core/tests/source/file_db_line_index.rs b/old-compiler/prometeu-core/tests/source/file_db_line_index.rs deleted file mode 100644 index df7e6893..00000000 --- a/old-compiler/prometeu-core/tests/source/file_db_line_index.rs +++ /dev/null @@ -1,69 +0,0 @@ -use prometeu_core::{FileDB, LineIndex}; - -#[test] -fn test_line_index_roundtrip() { - let text = "line 1\nline 2\nline 3"; - let index = LineIndex::new(text); - - // Roundtrip for each character - for (offset, _) in text.char_indices() { - let (line, col) = index.offset_to_line_col(offset as u32); - let recovered_offset = index.line_col_to_offset(line, col).expect("Should recover offset"); - assert_eq!(offset as u32, recovered_offset, "Offset mismatch at line {}, col {}", line, col); - } -} - -#[test] -fn test_line_index_boundaries() { - let text = "a\nbc\n"; - let index = LineIndex::new(text); - - // "a" -> (0, 0) - assert_eq!(index.offset_to_line_col(0), (0, 0)); - assert_eq!(index.line_col_to_offset(0, 0), Some(0)); - - // "\n" -> (0, 1) - assert_eq!(index.offset_to_line_col(1), (0, 1)); - assert_eq!(index.line_col_to_offset(0, 1), Some(1)); - - // "b" -> (1, 0) - assert_eq!(index.offset_to_line_col(2), (1, 0)); - assert_eq!(index.line_col_to_offset(1, 0), Some(2)); - - // "c" -> (1, 1) - assert_eq!(index.offset_to_line_col(3), (1, 1)); - assert_eq!(index.line_col_to_offset(1, 1), Some(3)); - - // "\n" (second) -> (1, 2) - assert_eq!(index.offset_to_line_col(4), (1, 2)); - assert_eq!(index.line_col_to_offset(1, 2), Some(4)); - - // EOF (after last \n) -> (2, 0) - assert_eq!(index.offset_to_line_col(5), (2, 0)); - assert_eq!(index.line_col_to_offset(2, 0), Some(5)); - - // Out of bounds - assert_eq!(index.line_col_to_offset(2, 1), None); - assert_eq!(index.line_col_to_offset(3, 0), None); -} - -#[test] -fn test_file_db_upsert_and_access() { - let mut db = FileDB::new(); - let uri = "file:///test.txt"; - let text = "hello\nworld".to_string(); - - let id = db.upsert(uri, text.clone()); - assert_eq!(db.file_id(uri), Some(id)); - assert_eq!(db.uri(id), uri); - assert_eq!(db.text(id), &text); - - let index = db.line_index(id); - assert_eq!(index.offset_to_line_col(6), (1, 0)); // 'w' is at offset 6 - - // Update existing file - let new_text = "new content".to_string(); - let same_id = db.upsert(uri, new_text.clone()); - assert_eq!(id, same_id); - assert_eq!(db.text(id), &new_text); -} diff --git a/old-compiler/prometeu-core/tests/source/span_tests.rs b/old-compiler/prometeu-core/tests/source/span_tests.rs deleted file mode 100644 index 657a975b..00000000 --- a/old-compiler/prometeu-core/tests/source/span_tests.rs +++ /dev/null @@ -1,14 +0,0 @@ -use prometeu_core::{FileId, Span}; - -#[test] -fn span_end_is_exclusive() { - let file = FileId(1); - let s = Span::new(file, 2, 5); - // len = end - start - assert_eq!(s.len(), 3); - // contains is [start, end) - assert!(s.contains(2)); - assert!(s.contains(3)); - assert!(s.contains(4)); - assert!(!s.contains(5)); -} diff --git a/old-compiler/prometeu-deps/Cargo.toml b/old-compiler/prometeu-deps/Cargo.toml deleted file mode 100644 index 9b923bd9..00000000 --- a/old-compiler/prometeu-deps/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "prometeu-deps" -version = "0.1.0" -edition = "2021" -license = "MIT" -description = "" - -[dependencies] -serde = { version = "1.0.228", features = ["derive"] } -prometeu-core = { path = "../prometeu-core" } -prometeu-language-api = { path = "../prometeu-language-api" } -prometeu-languages-registry = { path = "../languages/prometeu-languages-registry" } -anyhow = "1.0.101" -camino = "1.2.2" -walkdir = "2.5.0" -serde_json = "1.0.149" - -[features] -default = [] diff --git a/old-compiler/prometeu-deps/src/lib.rs b/old-compiler/prometeu-deps/src/lib.rs deleted file mode 100644 index 06b40cfb..00000000 --- a/old-compiler/prometeu-deps/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod model; -mod load_sources; -mod workspace; - -pub use workspace::resolve_workspace; -pub use load_sources::load_sources; - -pub use model::manifest::*; -pub use model::resolved_project::ResolvedWorkspace; -pub use model::deps_config::DepsConfig; -pub use model::project_descriptor::ProjectDescriptor; -pub use model::build_stack::BuildStack; -pub use model::resolved_graph::ResolvedGraph; -pub use model::loaded_sources::LoadedSources; -pub use model::project_sources::ProjectSources; -pub use model::loaded_file::LoadedFile; -pub use model::cache_blobs::CacheBlobs; -pub use model::cache_plan::CachePlan; - diff --git a/old-compiler/prometeu-deps/src/load_sources.rs b/old-compiler/prometeu-deps/src/load_sources.rs deleted file mode 100644 index 0a8c64b5..00000000 --- a/old-compiler/prometeu-deps/src/load_sources.rs +++ /dev/null @@ -1,97 +0,0 @@ -use anyhow::{Context, Result}; -use camino::Utf8PathBuf; -use walkdir::WalkDir; - -use crate::{ - DepsConfig, - LoadedFile, - LoadedSources, - ProjectSources, - ResolvedWorkspace, -}; - -pub fn load_sources(cfg: &DepsConfig, resolved: &ResolvedWorkspace) -> Result { - let mut per_project = Vec::with_capacity(resolved.stack.projects.len()); - - for project_id in &resolved.stack.projects { - let project = resolved - .graph - .project(project_id) - .with_context(|| format!("deps: unknown project_id {:?} in build stack", project_id))?; - - if cfg.explain { - eprintln!( - "[deps] load_sources: project {}@{} ({:?})", - project.name, project.version, project.project_dir - ); - } - - let mut files: Vec = Vec::new(); - - for root in &project.source_roots { - let abs_root = project.project_dir.join(root); - - if cfg.explain { - eprintln!("[deps] scanning {:?}", abs_root); - } - - if !abs_root.exists() { - anyhow::bail!( - "deps: source root does not exist for project {}@{}: {:?}", - project.name, - project.version, - abs_root - ); - } - - // Walk recursively. - for entry in WalkDir::new(&abs_root) - .follow_links(false) - .into_iter() - .filter_map(|e| e.ok()) - { - let ft = entry.file_type(); - if !ft.is_file() { - continue; - } - - let path = entry.path(); - - - // TODO: precisamos mexer no prometeu.json para configurar o frontend do projeto - // Filter extensions: start with PBS only. - if path.extension().and_then(|s| s.to_str()) != Some("pbs") { - continue; - } - - // Convert to Utf8Path (the best effort) and use a stable "uri". - let path_utf8: Utf8PathBuf = match Utf8PathBuf::from_path_buf(path.to_path_buf()) { - Ok(p) => p, - Err(_) => { - anyhow::bail!("deps: non-utf8 path found while scanning sources: {:?}", path); - } - }; - - let text = std::fs::read_to_string(&path_utf8) - .with_context(|| format!("deps: failed to read source file {:?}", path_utf8))?; - - // TODO: normalize newlines - - files.push(LoadedFile { - uri: path_utf8.to_string(), - text, - }); - } - } - - // Determinism: sort a file list by uri (important for stable builds). - files.sort_by(|a, b| a.uri.cmp(&b.uri)); - - per_project.push(ProjectSources { - project_id: project_id.clone(), - files, - }); - } - - Ok(LoadedSources { per_project }) -} diff --git a/old-compiler/prometeu-deps/src/model/build_stack.rs b/old-compiler/prometeu-deps/src/model/build_stack.rs deleted file mode 100644 index e3e85727..00000000 --- a/old-compiler/prometeu-deps/src/model/build_stack.rs +++ /dev/null @@ -1,6 +0,0 @@ -use prometeu_core::ProjectId; - -#[derive(Debug, Clone)] -pub struct BuildStack { - pub projects: Vec, -} diff --git a/old-compiler/prometeu-deps/src/model/cache_blobs.rs b/old-compiler/prometeu-deps/src/model/cache_blobs.rs deleted file mode 100644 index e92281eb..00000000 --- a/old-compiler/prometeu-deps/src/model/cache_blobs.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Cache blobs computed/validated by deps. -/// The pipeline may decide when to store, but deps executes IO and cache validity. -#[derive(Debug, Clone)] -pub struct CacheBlobs { - // placeholder - pub _unused: (), -} diff --git a/old-compiler/prometeu-deps/src/model/cache_plan.rs b/old-compiler/prometeu-deps/src/model/cache_plan.rs deleted file mode 100644 index be7f0236..00000000 --- a/old-compiler/prometeu-deps/src/model/cache_plan.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[derive(Debug, Clone)] -pub struct CachePlan { - -} \ No newline at end of file diff --git a/old-compiler/prometeu-deps/src/model/deps_config.rs b/old-compiler/prometeu-deps/src/model/deps_config.rs deleted file mode 100644 index e20e137e..00000000 --- a/old-compiler/prometeu-deps/src/model/deps_config.rs +++ /dev/null @@ -1,7 +0,0 @@ -use camino::Utf8PathBuf; - -pub struct DepsConfig { - pub explain: bool, - pub cache_dir: Utf8PathBuf, - pub registry_dirs: Vec, // or sources ? -} \ No newline at end of file diff --git a/old-compiler/prometeu-deps/src/model/loaded_file.rs b/old-compiler/prometeu-deps/src/model/loaded_file.rs deleted file mode 100644 index f1763402..00000000 --- a/old-compiler/prometeu-deps/src/model/loaded_file.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[derive(Debug, Clone)] -pub struct LoadedFile { - pub uri: String, - pub text: String, -} diff --git a/old-compiler/prometeu-deps/src/model/loaded_sources.rs b/old-compiler/prometeu-deps/src/model/loaded_sources.rs deleted file mode 100644 index b5cb3085..00000000 --- a/old-compiler/prometeu-deps/src/model/loaded_sources.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::model::project_sources::ProjectSources; - -/// Sources already loaded by deps (IO happens in deps, not in pipeline). -#[derive(Debug, Clone)] -pub struct LoadedSources { - /// For each project in the stack, a list of files (uri + text). - pub per_project: Vec, -} diff --git a/old-compiler/prometeu-deps/src/model/manifest.rs b/old-compiler/prometeu-deps/src/model/manifest.rs deleted file mode 100644 index 2404d945..00000000 --- a/old-compiler/prometeu-deps/src/model/manifest.rs +++ /dev/null @@ -1,75 +0,0 @@ -use camino::Utf8PathBuf; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Manifest { - pub name: String, - pub version: String, - - #[serde(default)] - pub source_roots: Vec, - - pub language: LanguageDecl, - - #[serde(default)] - pub deps: Vec, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct LanguageDecl { - pub id: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum DepDecl { - Local { - path: String, - }, - Git { - git: String, - rev: Option, - }, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PrometeuLock { - pub schema: u32, - #[serde(default)] - pub mappings: Vec, -} - -impl PrometeuLock { - pub fn blank() -> Self { - Self { - schema: 0, - mappings: vec![], - } - } - - pub fn lookup_git_local_dir(&self, url: &str, rev: &str) -> Option<&String> { - self.mappings.iter().find_map(|m| match m { - LockMapping::Git { - git, rev: r, local_dir - } if git == url && r == rev => Some(local_dir), - _ => None, - }) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum LockMapping { - Git { - git: String, - rev: String, - local_dir: String, - }, - Registry { - registry: String, - version: String, - local_dir: String, - }, -} - - diff --git a/old-compiler/prometeu-deps/src/model/mod.rs b/old-compiler/prometeu-deps/src/model/mod.rs deleted file mode 100644 index d75c23c6..00000000 --- a/old-compiler/prometeu-deps/src/model/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod deps_config; -pub mod project_descriptor; -pub mod build_stack; -pub mod resolved_graph; -pub mod loaded_sources; -pub mod project_sources; -pub mod loaded_file; -pub mod cache_blobs; -pub mod resolved_project; -pub mod cache_plan; -pub mod manifest; \ No newline at end of file diff --git a/old-compiler/prometeu-deps/src/model/project_descriptor.rs b/old-compiler/prometeu-deps/src/model/project_descriptor.rs deleted file mode 100644 index a1436312..00000000 --- a/old-compiler/prometeu-deps/src/model/project_descriptor.rs +++ /dev/null @@ -1,14 +0,0 @@ -use camino::Utf8PathBuf; -use prometeu_core::ProjectId; -use prometeu_language_api::SourcePolicy; - -#[derive(Debug, Clone)] -pub struct ProjectDescriptor { - pub project_id: ProjectId, - pub name: String, - pub version: String, - pub project_dir: Utf8PathBuf, - pub source_roots: Vec, - pub language_id: String, - pub source_policy: SourcePolicy, -} diff --git a/old-compiler/prometeu-deps/src/model/project_sources.rs b/old-compiler/prometeu-deps/src/model/project_sources.rs deleted file mode 100644 index 8034b9c3..00000000 --- a/old-compiler/prometeu-deps/src/model/project_sources.rs +++ /dev/null @@ -1,8 +0,0 @@ -use prometeu_core::ProjectId; -use crate::model::loaded_file::LoadedFile; - -#[derive(Debug, Clone)] -pub struct ProjectSources { - pub project_id: ProjectId, - pub files: Vec, -} diff --git a/old-compiler/prometeu-deps/src/model/resolved_graph.rs b/old-compiler/prometeu-deps/src/model/resolved_graph.rs deleted file mode 100644 index 357b088e..00000000 --- a/old-compiler/prometeu-deps/src/model/resolved_graph.rs +++ /dev/null @@ -1,16 +0,0 @@ -use prometeu_core::ProjectId; -use crate::ProjectDescriptor; - -#[derive(Debug, Clone)] -pub struct ResolvedGraph { - pub root: ProjectId, - pub projects: Vec, // arena - // opcional: adjacency list para checks - pub edges: Vec>, // edges[from] = vec[to] -} - -impl ResolvedGraph { - pub fn project(&self, id: &ProjectId) -> Option<&ProjectDescriptor> { - self.projects.get(id.0 as usize) - } -} diff --git a/old-compiler/prometeu-deps/src/model/resolved_project.rs b/old-compiler/prometeu-deps/src/model/resolved_project.rs deleted file mode 100644 index a9af9f3d..00000000 --- a/old-compiler/prometeu-deps/src/model/resolved_project.rs +++ /dev/null @@ -1,9 +0,0 @@ -use prometeu_core::ProjectId; -use crate::{BuildStack, ResolvedGraph}; - -#[derive(Debug, Clone)] -pub struct ResolvedWorkspace { - pub project_id: ProjectId, - pub graph: ResolvedGraph, - pub stack: BuildStack, -} diff --git a/old-compiler/prometeu-deps/src/workspace/host.rs b/old-compiler/prometeu-deps/src/workspace/host.rs deleted file mode 100644 index 19335c27..00000000 --- a/old-compiler/prometeu-deps/src/workspace/host.rs +++ /dev/null @@ -1,32 +0,0 @@ -use anyhow::{Context, Result}; -use camino::{Utf8Path, Utf8PathBuf}; - -use crate::workspace::model::DepRef; - -pub trait DepsHost { - fn read_to_string(&self, path: &Utf8Path) -> Result; - - // fn ensure_project_local(&self, from_dir: &Utf8Path, dep: &DepRef) -> Result; -} - -pub struct FsHost; - -impl DepsHost for FsHost { - fn read_to_string(&self, path: &Utf8Path) -> Result { - std::fs::read_to_string(path) - .with_context(|| format!("failed to read {:?}", path)) - } - - // fn ensure_project_local(&self, from_dir: &Utf8Path, dep: &DepRef) -> Result { - // match dep { - // DepRef::Local { path } => { - // let joined = from_dir.join(path); - // let canon = joined.canonicalize() - // .with_context(|| format!("deps: dep path does not exist: {:?}", joined))?; - // Utf8PathBuf::from_path_buf(canon) - // .map_err(|p| anyhow::anyhow!("deps: non-utf8 dep dir: {:?}", p)) - // } - // _ => unimplemented!(), - // } - // } -} diff --git a/old-compiler/prometeu-deps/src/workspace/mod.rs b/old-compiler/prometeu-deps/src/workspace/mod.rs deleted file mode 100644 index 944786d8..00000000 --- a/old-compiler/prometeu-deps/src/workspace/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod resolve_workspace; -mod host; -mod model; -mod phases; - -pub use resolve_workspace::resolve_workspace; \ No newline at end of file diff --git a/old-compiler/prometeu-deps/src/workspace/model.rs b/old-compiler/prometeu-deps/src/workspace/model.rs deleted file mode 100644 index ddd6e65e..00000000 --- a/old-compiler/prometeu-deps/src/workspace/model.rs +++ /dev/null @@ -1,31 +0,0 @@ -use camino::Utf8PathBuf; -use prometeu_core::ProjectId; -use prometeu_language_api::SourcePolicy; - -use crate::Manifest; - -#[derive(Debug, Clone)] -pub struct RawProjectNode { - pub dir: Utf8PathBuf, - pub manifest_path: Utf8PathBuf, - pub manifest: Manifest, -} - -#[derive(Debug, Clone)] -pub enum DepRef { - Local { - path: Utf8PathBuf - }, -} - -#[derive(Debug, Clone)] -pub struct ProjectNode { - pub id: ProjectId, - pub dir: Utf8PathBuf, - pub name: String, - pub version: String, - pub source_roots: Vec, - pub language_id: String, - pub deps: Vec, - pub source_policy: SourcePolicy, -} diff --git a/old-compiler/prometeu-deps/src/workspace/phases/discover.rs b/old-compiler/prometeu-deps/src/workspace/phases/discover.rs deleted file mode 100644 index 51184a08..00000000 --- a/old-compiler/prometeu-deps/src/workspace/phases/discover.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::model::manifest::DepDecl; -use crate::workspace::host::DepsHost; -use crate::workspace::model::RawProjectNode; -use crate::workspace::phases::state::ResolverState; -use crate::Manifest; -use anyhow::{anyhow, bail, Context, Result}; -use camino::Utf8PathBuf; -use serde_json; -use std::fs::canonicalize; - -/// Phase 1: Discover all projects in the workspace. -/// -/// - Reads `prometeu.json` from each pending project directory. -/// - Parses `Manifest`. -/// - Registers the raw node. -/// - Enqueues local-path deps for discovery (v0). -/// -/// Does NOT: -/// - assign ProjectId -/// - build edges -/// - validate versions -pub fn discover( - cfg: &crate::DepsConfig, - host: &dyn DepsHost, - state: &mut ResolverState, -) -> Result<()> { - while let Some(canon_dir) = state.pending.pop_front() { - // de-dup by directory - if state.raw_by_dir.contains_key(&canon_dir) { - continue; - } - - let manifest_path = canon_dir.join("prometeu.json"); - if !manifest_path.exists() || !manifest_path.is_file() { - bail!( - "deps: manifest not found: expected a file {:?} (project dir {:?})", - manifest_path, - canon_dir - ); - } - - if cfg.explain { - eprintln!("[deps][discover] reading {:?}", manifest_path); - } - - let text = host - .read_to_string(&manifest_path) - .with_context(|| format!("deps: failed to read manifest {:?}", manifest_path))?; - - let manifest: Manifest = serde_json::from_str(&text) - .with_context(|| format!("deps: invalid manifest JSON {:?}", manifest_path))?; - - // Register raw node - let raw_idx = state.raw.len(); - state.raw.push(RawProjectNode { - dir: canon_dir.clone(), - manifest_path: manifest_path.clone(), - manifest: manifest.clone(), - }); - state.raw_by_dir.insert(canon_dir.clone(), raw_idx); - - for dep in &manifest.deps { - match dep { - DepDecl::Local { path } => { - let dep_dir = canon_dir.join(path); - - let dep_dir_std = dep_dir.canonicalize().with_context(|| { - format!( - "deps: dep path does not exist: {:?} (from {:?})", - dep_dir, canon_dir - ) - })?; - - let dep_dir_canon = Utf8PathBuf::from_path_buf(dep_dir_std) - .map_err(|p| anyhow!("deps: non-utf8 dep dir: {:?}", p))?; - - if cfg.explain { - eprintln!("[deps][discover] local dep '{}' -> {:?}", path, dep_dir_canon); - } - state.pending.push_back(dep_dir_canon); - } - - DepDecl::Git { git, rev } => { - let Some(rev) = rev.as_deref() else { - bail!( - "deps: git dependency '{}' requires an explicit 'rev' (commit hash) for now", - git - ); - }; - - let Some(local_dir) = state.lock.lookup_git_local_dir(git, rev) else { - bail!( - "deps: git dependency requires prometeu.lock mapping, but entry not found: git='{}' rev='{}'", - git, - rev - ); - }; - - // canonicalize the lock-provided local dir to keep identity stable - let local_dir_std = canonicalize(local_dir) - .with_context(|| format!("deps: prometeu.lock local_dir does not exist: {:?}", local_dir))?; - - let local_dir_canon = Utf8PathBuf::from_path_buf(local_dir_std) - .map_err(|p| anyhow!("deps: non-utf8 lock local_dir: {:?}", p))?; - - // validate manifest exists at the mapped project root - // (this check should not belong here, but it is ok) - let mapped_manifest = local_dir_canon.join("prometeu.json"); - if !mapped_manifest.exists() || !mapped_manifest.is_file() { - bail!( - "deps: prometeu.lock maps git dep to {:?}, but manifest is missing: {:?}", - local_dir_canon, - mapped_manifest - ); - } - - if cfg.explain { - eprintln!( - "[deps][discover] git dep '{}' rev '{}' -> {:?}", - git, rev, local_dir_canon - ); - } - - state.pending.push_back(local_dir_canon); - } - } - } - } - - Ok(()) -} diff --git a/old-compiler/prometeu-deps/src/workspace/phases/localize.rs b/old-compiler/prometeu-deps/src/workspace/phases/localize.rs deleted file mode 100644 index aa900bc1..00000000 --- a/old-compiler/prometeu-deps/src/workspace/phases/localize.rs +++ /dev/null @@ -1,62 +0,0 @@ -use anyhow::{Context, Result}; - -use prometeu_core::ProjectId; - -use crate::workspace::model::DepRef; -use crate::workspace::phases::state::ResolverState; - -/// Phase 3: Localize dependencies and build graph edges. -/// -/// For each project node: -/// - For each DepRef: -/// - host.ensure_project_local(from_dir, dep) -> dep_dir (local on disk) -/// - map dep_dir to ProjectId via st.by_dir -/// - st.edges[from].push(dep_id) -/// -/// v0 policy: -/// - Only DepRef::LocalPath is supported. -/// - Git/Registry cause a hard error (future extension point). -pub fn localize(cfg: &crate::DepsConfig, state: &mut ResolverState) -> Result<()> { - // Reset edges (allows re-run / deterministic behavior) - for e in &mut state.edges { - e.clear(); - } - - for from_idx in 0..state.nodes.len() { - let from_id: ProjectId = state.nodes[from_idx].id; - let from_dir = state.nodes[from_idx].dir.clone(); - - if cfg.explain { - eprintln!( - "[deps][localize] from id={:?} dir={:?}", - from_id, from_dir - ); - } - - // Clone deps to avoid borrow conflicts (simple + safe for now) - let deps = state.nodes[from_idx].deps.clone(); - - for dep in deps { - match &dep { - DepRef::Local { - path - } => { - let dep_id = state.by_dir.get(path).copied().with_context(|| { - format!( - "deps: localized dep dir {:?} was not discovered; \ - ensure the dep has a prometeu.json and is reachable via local paths", - path - ) - })?; - state.edges[from_id.0 as usize].push(dep_id); - } - } - } - - // Optional: keep edges deterministic - state.edges[from_id.0 as usize].sort_by_key(|id| id.0); - state.edges[from_id.0 as usize].dedup(); - } - - Ok(()) -} diff --git a/old-compiler/prometeu-deps/src/workspace/phases/materialize.rs b/old-compiler/prometeu-deps/src/workspace/phases/materialize.rs deleted file mode 100644 index 7aca4ddd..00000000 --- a/old-compiler/prometeu-deps/src/workspace/phases/materialize.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::model::manifest::DepDecl; -use crate::workspace::model::{DepRef, ProjectNode}; -use crate::workspace::phases::state::ResolverState; -use anyhow::{anyhow, bail, Context, Result}; -use camino::Utf8PathBuf; -use prometeu_core::ProjectId; -use prometeu_languages_registry::get_language_spec; -use std::fs::canonicalize; - -/// Phase 2: Materialize projects (allocate ProjectId / arena nodes). -/// -/// Inputs: -/// - st.raw (RawProjectNode: dir + manifest) -/// -/// Outputs: -/// - st.nodes (ProjectNode arena) -/// - st.by_dir (dir -> ProjectId) -/// - st.edges (allocated adjacency lists, empty for now) -/// - st.root (ProjectId for root_dir) -/// -/// Does NOT: -/// - resolve deps to local dirs (that's phase localize) -/// - validate version conflicts/cycles -/// - resolve language/source policy -pub fn materialize(cfg: &crate::DepsConfig, state: &mut ResolverState) -> Result<()> { - // Reset materialized state (allows rerun in future refactors/tests) - state.nodes.clear(); - state.by_dir.clear(); - state.edges.clear(); - state.root = None; - - state.nodes.reserve(state.raw.len()); - state.edges.reserve(state.raw.len()); - - for (idx, raw) in state.raw.iter().enumerate() { - let id = ProjectId(idx as u32); - - // Default source roots if omitted - let source_roots: Vec = raw - .manifest - .source_roots - .iter() - .map(|root| Utf8PathBuf::from(root)) - .collect(); - if source_roots.is_empty() { - bail!( - "deps: no source roots specified for project {}", - raw.manifest.name - ) - } - - // Convert DepDecl -> DepRef (no localization yet) - let mut deps: Vec = Vec::with_capacity(raw.manifest.deps.len()); - for d in &raw.manifest.deps { - match d { - DepDecl::Local { path } => { - let joined = raw.dir.join(path); - let dir_std = joined.canonicalize() - .with_context(|| format!("deps: local dep path does not exist: {:?} (from {:?})", joined, raw.dir))?; - - let dir_canon = Utf8PathBuf::from_path_buf(dir_std) - .map_err(|p| anyhow!("deps: non-utf8 dep dir: {:?}", p))?; - deps.push(DepRef::Local { - path: dir_canon - }); - } - DepDecl::Git { git, rev } => { - let Some(rev) = rev.as_deref() else { - bail!( - "deps: git dependency '{}' requires an explicit 'rev' (commit hash) for now", - git - ); - }; - - let Some(local_dir) = state.lock.lookup_git_local_dir(git, rev) else { - bail!( - "deps: git dependency requires prometeu.lock mapping, but entry not found: git='{}' rev='{}'", - git, - rev - ); - }; - - // canonicalize the lock-provided local dir to keep identity stable - let path = canonicalize(local_dir).with_context(|| { - format!( - "deps: prometeu.lock local_dir does not exist: {:?}", - local_dir - ) - })?; - - let local_dir_canon = Utf8PathBuf::from_path_buf(path) - .map_err(|p| anyhow!("deps: non-utf8 lock local_dir: {:?}", p))?; - - deps.push(DepRef::Local { - path: local_dir_canon, - }); - } - } - } - - if cfg.explain { - eprintln!( - "[deps][materialize] id={:?} {}@{} dir={:?} language={}", - id, raw.manifest.name, raw.manifest.version, raw.dir, raw.manifest.language.id - ); - } - - let source_policy = get_language_spec(raw.manifest.language.id.as_str()) - .map(|spec| spec.source_policy.clone()) - .ok_or(anyhow!( - "deps: unknown language spec: {}", - raw.manifest.language.id - ))?; - - // Record node - state.nodes.push(ProjectNode { - id, - dir: raw.dir.clone(), - name: raw.manifest.name.clone(), - version: raw.manifest.version.clone(), - source_roots, - language_id: raw.manifest.language.id.clone(), - deps, - source_policy, - }); - - state.by_dir.insert(raw.dir.clone(), id); - state.edges.push(Vec::new()); - } - - // Determine root id - if let Some(root_id) = state.by_dir.get(&state.root_dir).copied() { - state.root = Some(root_id); - } else { - // This should never happen if seed/discover worked. - // Keep it as a hard failure (in a later validate phase you can convert to a nicer diagnostic). - anyhow::bail!( - "deps: root project dir {:?} was not discovered/materialized", - state.root_dir - ); - } - - Ok(()) -} diff --git a/old-compiler/prometeu-deps/src/workspace/phases/mod.rs b/old-compiler/prometeu-deps/src/workspace/phases/mod.rs deleted file mode 100644 index 25fbb3e4..00000000 --- a/old-compiler/prometeu-deps/src/workspace/phases/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -mod run_all; -mod state; -mod discover; -mod materialize; -mod localize; -mod validate; -mod policy; -mod stack; - -pub use run_all::run_all; \ No newline at end of file diff --git a/old-compiler/prometeu-deps/src/workspace/phases/policy.rs b/old-compiler/prometeu-deps/src/workspace/phases/policy.rs deleted file mode 100644 index f2340ef7..00000000 --- a/old-compiler/prometeu-deps/src/workspace/phases/policy.rs +++ /dev/null @@ -1,17 +0,0 @@ -use anyhow::{bail, Result}; - -use crate::workspace::phases::state::ResolverState; - -pub fn policy(_cfg: &crate::DepsConfig, state: &mut ResolverState) -> Result<()> { - for node in &state.nodes { - if node.source_policy.extensions.is_empty() { - bail!( - "deps: project {}@{} has empty source_policy.extensions (language={})", - node.name, - node.version, - node.language_id - ); - } - } - Ok(()) -} diff --git a/old-compiler/prometeu-deps/src/workspace/phases/run_all.rs b/old-compiler/prometeu-deps/src/workspace/phases/run_all.rs deleted file mode 100644 index 62d71d6b..00000000 --- a/old-compiler/prometeu-deps/src/workspace/phases/run_all.rs +++ /dev/null @@ -1,50 +0,0 @@ -use anyhow::{Context, Result}; -use camino::Utf8Path; - -use crate::{BuildStack, DepsConfig, ProjectDescriptor, ResolvedGraph, ResolvedWorkspace}; -use crate::workspace::host::FsHost; -use crate::workspace::phases::{discover, localize, materialize, policy, stack, state, validate}; - -pub fn run_all(cfg: &DepsConfig, fs_host: &FsHost, root_dir: &Utf8Path) -> Result { - let mut st = state::seed(cfg, root_dir)?; - - discover::discover(cfg, fs_host, &mut st)?; - materialize::materialize(cfg, &mut st)?; - localize::localize(cfg, &mut st)?; - - validate::validate(cfg, &st)?; - policy::policy(cfg, &mut st)?; - - let build_stack: BuildStack = stack::stack(cfg, &mut st)?; - - let root = st - .root - .context("deps: internal error: root ProjectId not set")?; - - // Build the arena expected by ResolvedGraph: index == ProjectId.0 - // materialize already assigns ProjectId(idx), so st.nodes order is stable. - let mut projects: Vec = Vec::with_capacity(st.nodes.len()); - for n in &st.nodes { - projects.push(ProjectDescriptor { - project_id: n.id, - name: n.name.clone(), - version: n.version.clone(), - project_dir: n.dir.clone(), - source_roots: n.source_roots.clone(), - language_id: n.language_id.clone(), - source_policy: n.source_policy.clone(), - }); - } - - let graph = ResolvedGraph { - root, - projects, - edges: st.edges, - }; - - Ok(ResolvedWorkspace { - project_id: root, - graph, - stack: build_stack, - }) -} diff --git a/old-compiler/prometeu-deps/src/workspace/phases/stack.rs b/old-compiler/prometeu-deps/src/workspace/phases/stack.rs deleted file mode 100644 index 34e5e49a..00000000 --- a/old-compiler/prometeu-deps/src/workspace/phases/stack.rs +++ /dev/null @@ -1,97 +0,0 @@ -use anyhow::{Context, Result}; -use prometeu_core::ProjectId; -use std::collections::VecDeque; -use crate::BuildStack; -use crate::workspace::phases::state::ResolverState; - -/// Phase: BuildStack (deps-first topo order). -/// -/// Output: -/// - state.stack: Vec where deps appear before dependents. -/// -/// Determinism: -/// - ties are resolved by ProjectId order (stable across runs if discovery is stable). -pub fn stack(cfg: &crate::DepsConfig, state: &mut ResolverState) -> Result { - let n = state.nodes.len(); - let _root = state.root.context("deps: internal error: root ProjectId not set")?; - - // Build indegree - let mut indeg = vec![0usize; n]; - for outs in &state.edges { - for &to in outs { - indeg[to.0 as usize] += 1; - } - } - - // Deterministic queue: push in ProjectId order - let mut q = VecDeque::new(); - for i in 0..n { - if indeg[i] == 0 { - q.push_back(i); - } - } - - let mut order: Vec = Vec::with_capacity(n); - - while let Some(i) = q.pop_front() { - order.push(ProjectId(i as u32)); - - // Ensure deterministic traversal of outgoing edges too - // (your localize already sort/dedup edges, but this doesn't hurt) - for &to in &state.edges[i] { - let j = to.0 as usize; - indeg[j] -= 1; - if indeg[j] == 0 { - // Deterministic insert: keep queue ordered by ProjectId - // Simple O(n) insertion is fine for now. - insert_sorted_by_id(&mut q, j); - } - } - } - - // If validate ran, this should already be cycle-free; still keep a guard. - if order.len() != n { - anyhow::bail!( - "deps: internal error: stack generation did not visit all nodes ({} of {})", - order.len(), - n - ); - } - - if cfg.explain { - eprintln!("[deps][stack] build order:"); - for id in &order { - let node = &state.nodes[id.0 as usize]; - eprintln!(" - {:?} {}@{} dir={:?}", id, node.name, node.version, node.dir); - } - } - - Ok(BuildStack { - projects: order, - }) -} - -/// Insert node index `i` into queue `q` keeping it sorted by ProjectId (index). -fn insert_sorted_by_id(q: &mut VecDeque, i: usize) { - // Common fast path: append if >= last - if let Some(&last) = q.back() { - if i >= last { - q.push_back(i); - return; - } - } - - // Otherwise find insertion point - let mut pos = 0usize; - for &v in q.iter() { - if i < v { - break; - } - pos += 1; - } - - // VecDeque has no insert, so rebuild (small sizes OK for hard reset) - let mut tmp: Vec = q.drain(..).collect(); - tmp.insert(pos, i); - *q = VecDeque::from(tmp); -} diff --git a/old-compiler/prometeu-deps/src/workspace/phases/state.rs b/old-compiler/prometeu-deps/src/workspace/phases/state.rs deleted file mode 100644 index 5eef4842..00000000 --- a/old-compiler/prometeu-deps/src/workspace/phases/state.rs +++ /dev/null @@ -1,58 +0,0 @@ -use camino::{Utf8Path, Utf8PathBuf}; -use std::collections::{HashMap, VecDeque}; -use anyhow::Context; -use crate::workspace::model::{RawProjectNode, ProjectNode}; -use prometeu_core::ProjectId; -use crate::PrometeuLock; -use serde_json; - -pub struct ResolverState { - pub root_dir: Utf8PathBuf, - - // phase1 output - pub raw: Vec, - pub raw_by_dir: HashMap, - pub pending: VecDeque, - - // phase2+ - pub nodes: Vec, - pub by_dir: HashMap, - pub edges: Vec>, - - pub root: Option, - - pub lock: PrometeuLock, -} - -pub fn seed(_cfg: &crate::DepsConfig, root_dir: &Utf8Path) -> anyhow::Result { - let path_buf = root_dir.canonicalize()?; - let root_dir_canon = Utf8PathBuf::from_path_buf(path_buf) - .map_err(|p| anyhow::anyhow!("deps: non-utf8 root dir: {:?}", p))?; - - let lock_path = root_dir_canon.join("prometeu.lock"); - let lock = if lock_path.exists() { - let txt = std::fs::read_to_string(&lock_path)?; - serde_json::from_str::(&txt) - .with_context(|| format!("invalid prometeu.lock at {:?}", lock_path))? - } else { - PrometeuLock::blank() - }; - - let mut pending = VecDeque::new(); - pending.push_back(root_dir_canon.clone()); - - Ok(ResolverState { - root_dir: root_dir_canon.clone(), - raw: vec![], - raw_by_dir: HashMap::new(), - pending, - - nodes: vec![], - by_dir: HashMap::new(), - edges: vec![], - - root: None, - - lock, - }) -} diff --git a/old-compiler/prometeu-deps/src/workspace/phases/validate.rs b/old-compiler/prometeu-deps/src/workspace/phases/validate.rs deleted file mode 100644 index b49a61ff..00000000 --- a/old-compiler/prometeu-deps/src/workspace/phases/validate.rs +++ /dev/null @@ -1,108 +0,0 @@ -use anyhow::{bail, Context, Result}; -use prometeu_core::ProjectId; -use std::collections::{HashMap, VecDeque}; - -use crate::workspace::phases::state::ResolverState; - -/// Phase: Validate workspace graph & invariants (v0). -/// -/// Checks: -/// - root present -/// - edges are in-range -/// - no cycles -/// - no version conflicts for same project name -pub fn validate(cfg: &crate::DepsConfig, state: &ResolverState) -> Result<()> { - // 1) root present - let root = state.root.context("deps: internal error: root ProjectId not set")?; - if cfg.explain { - eprintln!("[deps][validate] root={:?}", root); - } - - // 2) edges sanity - let n = state.nodes.len(); - for (from_idx, outs) in state.edges.iter().enumerate() { - for &to in outs { - let to_idx = to.0 as usize; - if to_idx >= n { - bail!( - "deps: invalid edge: from {:?} -> {:?} (to out of range; nodes={})", - ProjectId(from_idx as u32), - to, - n - ); - } - } - } - - // 3) version conflicts by name - // name -> (version -> ProjectId) - let mut by_name: HashMap<&str, HashMap<&str, ProjectId>> = HashMap::new(); - for node in &state.nodes { - let vmap = by_name.entry(node.name.as_str()).or_default(); - vmap.entry(node.version.as_str()).or_insert(node.id); - } - for (name, versions) in &by_name { - if versions.len() > 1 { - // create deterministic message - let mut vs: Vec<(&str, ProjectId)> = versions.iter().map(|(v, id)| (*v, *id)).collect(); - vs.sort_by(|a, b| a.0.cmp(b.0)); - - let mut msg = format!("deps: version conflict for project '{}':", name); - for (v, id) in vs { - let dir = &state.nodes[id.0 as usize].dir; - msg.push_str(&format!("\n - {} at {:?} (id={:?})", v, dir, id)); - } - bail!(msg); - } - } - - // 4) cycle detection (Kahn + leftover nodes) - // Build indegree - let mut indeg = vec![0usize; n]; - for outs in &state.edges { - for &to in outs { - indeg[to.0 as usize] += 1; - } - } - - let mut q = VecDeque::new(); - for i in 0..n { - if indeg[i] == 0 { - q.push_back(i); - } - } - - let mut visited = 0usize; - while let Some(i) = q.pop_front() { - visited += 1; - for &to in &state.edges[i] { - let j = to.0 as usize; - indeg[j] -= 1; - if indeg[j] == 0 { - q.push_back(j); - } - } - } - - if visited != n { - // Nodes with indeg>0 are part of cycles (or downstream of them) - let mut cyclic: Vec = Vec::new(); - for i in 0..n { - if indeg[i] > 0 { - cyclic.push(ProjectId(i as u32)); - } - } - - // Deterministic error output - cyclic.sort_by_key(|id| id.0); - - let mut msg = "deps: dependency cycle detected among:".to_string(); - for id in cyclic { - let node = &state.nodes[id.0 as usize]; - msg.push_str(&format!("\n - {:?} {}@{} dir={:?}", id, node.name, node.version, node.dir)); - } - bail!(msg); - } - - Ok(()) -} diff --git a/old-compiler/prometeu-deps/src/workspace/resolve_workspace.rs b/old-compiler/prometeu-deps/src/workspace/resolve_workspace.rs deleted file mode 100644 index 8e595efb..00000000 --- a/old-compiler/prometeu-deps/src/workspace/resolve_workspace.rs +++ /dev/null @@ -1,10 +0,0 @@ -use anyhow::Result; -use camino::Utf8Path; - -use crate::{DepsConfig, ResolvedWorkspace}; -use crate::workspace::host::FsHost; - -pub fn resolve_workspace(cfg: &DepsConfig, root_dir: &Utf8Path) -> Result { - let host = FsHost; - crate::workspace::phases::run_all(cfg, &host, root_dir) -} diff --git a/old-compiler/prometeu-language-api/Cargo.toml b/old-compiler/prometeu-language-api/Cargo.toml deleted file mode 100644 index 880c247e..00000000 --- a/old-compiler/prometeu-language-api/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "prometeu-language-api" -version = "0.1.0" -edition = "2021" -license = "MIT" -description = "Canonical language contract for Prometeu Backend: identifiers, references, and strict Frontend trait." -repository = "https://github.com/prometeu/runtime" - -[dependencies] - diff --git a/old-compiler/prometeu-language-api/src/language_spec.rs b/old-compiler/prometeu-language-api/src/language_spec.rs deleted file mode 100644 index ed1ff031..00000000 --- a/old-compiler/prometeu-language-api/src/language_spec.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[derive(Debug, Clone)] -pub struct SourcePolicy { - pub extensions: Vec<&'static str>, - pub case_sensitive: bool, -} - -impl SourcePolicy { - pub fn matches_ext(&self, ext: &str) -> bool { - if self.case_sensitive { - self.extensions.iter().any(|e| *e == ext) - } else { - self.extensions.iter().any(|e| e.eq_ignore_ascii_case(ext)) - } - } -} - -#[derive(Debug, Clone)] -pub struct LanguageSpec { - pub id: &'static str, - pub source_policy: SourcePolicy, -} \ No newline at end of file diff --git a/old-compiler/prometeu-language-api/src/lib.rs b/old-compiler/prometeu-language-api/src/lib.rs deleted file mode 100644 index 522059e9..00000000 --- a/old-compiler/prometeu-language-api/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod language_spec; - -pub use language_spec::*; diff --git a/old-compiler/prometeu-lowering/Cargo.toml b/old-compiler/prometeu-lowering/Cargo.toml deleted file mode 100644 index 60035bed..00000000 --- a/old-compiler/prometeu-lowering/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "prometeu-lowering" -version = "0.1.0" -edition = "2021" -license.workspace = true -repository.workspace = true - -[dependencies] -prometeu-bytecode = { path = "../prometeu-bytecode" } -prometeu-core = { path = "../prometeu-core" } -prometeu-language-api = { path = "../prometeu-language-api" } -clap = { version = "4.5.54", features = ["derive"] } -serde = { version = "1.0.228", features = ["derive"] } -serde_json = "1.0.149" -anyhow = "1.0.100" -pathdiff = "0.2.1" - -[dev-dependencies] -tempfile = "3.10.1" diff --git a/old-compiler/prometeu-lowering/src/lib.rs b/old-compiler/prometeu-lowering/src/lib.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/build.gradle.kts b/prometeu-compiler/frontends/prometeu-frontend-pbs/build.gradle.kts new file mode 100644 index 00000000..7b46f191 --- /dev/null +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("gradle.java-library-conventions") +} + +dependencies { + implementation(project(":prometeu-infra")) + + implementation(project(":prometeu-compiler:prometeu-compiler-core")) +} \ No newline at end of file diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSDefinitions.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSDefinitions.java new file mode 100644 index 00000000..413361ef --- /dev/null +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSDefinitions.java @@ -0,0 +1,13 @@ +package p.studio.compiler; + +import p.studio.compiler.model.FrontendSpec; +import p.studio.utilities.structures.ReadOnlySet; + +public class PBSDefinitions { + public static final FrontendSpec PBS = FrontendSpec + .builder() + .languageId("pbs") + .allowedExtensions(ReadOnlySet.from("pbs")) + .sourceRoots(ReadOnlySet.from("src")) + .build(); +} diff --git a/prometeu-compiler/build.gradle.kts b/prometeu-compiler/prometeu-build-pipeline/build.gradle.kts similarity index 100% rename from prometeu-compiler/build.gradle.kts rename to prometeu-compiler/prometeu-build-pipeline/build.gradle.kts diff --git a/prometeu-compiler/prometeu-compiler-core/build.gradle.kts b/prometeu-compiler/prometeu-compiler-core/build.gradle.kts new file mode 100644 index 00000000..8874f7a8 --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("gradle.java-library-conventions") +} + +dependencies { + api(project(":prometeu-infra")) +} \ No newline at end of file diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/model/FrontendSpec.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/model/FrontendSpec.java new file mode 100644 index 00000000..ca8630d9 --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/model/FrontendSpec.java @@ -0,0 +1,13 @@ +package p.studio.compiler.model; + +import lombok.Builder; +import lombok.Getter; +import p.studio.utilities.structures.ReadOnlySet; + +@Builder +@Getter +public class FrontendSpec { + private final String languageId; + private final ReadOnlySet allowedExtensions; + private final ReadOnlySet sourceRoots; +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/Span.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/Span.java new file mode 100644 index 00000000..fe177cbb --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/Span.java @@ -0,0 +1,34 @@ +package p.studio.compiler.source; + +import lombok.Getter; +import p.studio.compiler.source.identifiers.FileId; + +@Getter +public class Span { + private final FileId fileId; + private final long start; + private final long end; // exclusive + + public Span(FileId fileId, long start, long end) { + this.fileId = fileId; + this.start = Math.min(start, end); + this.end = Math.max(start, end); + } + + public static Span none() { + return new Span(FileId.none(), 0, 0); + } + + public boolean isNone() { + return fileId.isNone(); + } + + public long length() { + return end - start; + } + + public boolean contains(long pos) { + if (pos < 0L) return false; + return start <= pos && end > pos; + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/Diagnostic.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/Diagnostic.java new file mode 100644 index 00000000..ed05faba --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/Diagnostic.java @@ -0,0 +1,29 @@ +package p.studio.compiler.source.diagnostics; + +import lombok.Getter; +import p.studio.compiler.source.Span; +import p.studio.utilities.structures.ReadOnlyList; + +import java.util.List; + +@Getter +public class Diagnostic { + private final Severity severity; + private final String code; + private final String message; + private final Span span; + private final ReadOnlyList related; + + public Diagnostic( + final Severity severity, + final String code, + final String message, + final Span span, + final List related) { + this.severity = severity; + this.code = code; + this.message = message; + this.span = span; + this.related = ReadOnlyList.wrap(related); + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/DiagnosticBundle.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/DiagnosticBundle.java new file mode 100644 index 00000000..db06f548 --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/DiagnosticBundle.java @@ -0,0 +1,4 @@ +package p.studio.compiler.source.diagnostics; + +public class DiagnosticBundle { +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/RelatedSpan.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/RelatedSpan.java new file mode 100644 index 00000000..955193cb --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/RelatedSpan.java @@ -0,0 +1,15 @@ +package p.studio.compiler.source.diagnostics; + +import lombok.Getter; +import p.studio.compiler.source.Span; + +@Getter +public class RelatedSpan { + private final String message; + private final Span span; + + public RelatedSpan(String message, Span span) { + this.message = message; + this.span = span; + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/Severity.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/Severity.java new file mode 100644 index 00000000..ec80b2aa --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/diagnostics/Severity.java @@ -0,0 +1,11 @@ +package p.studio.compiler.source.diagnostics; + +public enum Severity { + Error, + Warning, + ; + + public boolean isError() { + return this == Error; + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/AbstractSourceIdentifier.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/AbstractSourceIdentifier.java new file mode 100644 index 00000000..d988ed11 --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/AbstractSourceIdentifier.java @@ -0,0 +1,24 @@ +package p.studio.compiler.source.identifiers; + +import lombok.EqualsAndHashCode; +import lombok.Getter; + +@Getter +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +abstract class AbstractSourceIdentifier { + @EqualsAndHashCode.Include + private final long id; + + AbstractSourceIdentifier(long id) { + this.id = id; + } + + public int getIndex() { + return (int) id; + } + + @Override + public String toString() { + return String.format("%s(%d)", getClass().getSimpleName(), id); + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/FileId.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/FileId.java new file mode 100644 index 00000000..1472d0f9 --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/FileId.java @@ -0,0 +1,17 @@ +package p.studio.compiler.source.identifiers; + +public class FileId extends AbstractSourceIdentifier { + public static final FileId NONE = new FileId(-1L); + + public FileId(long id) { + super(id); + } + + public static FileId none() { + return NONE; + } + + public boolean isNone() { + return this == NONE; + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/ModuleId.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/ModuleId.java new file mode 100644 index 00000000..90ec7812 --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/ModuleId.java @@ -0,0 +1,7 @@ +package p.studio.compiler.source.identifiers; + +public class ModuleId extends AbstractSourceIdentifier { + public ModuleId(long id) { + super(id); + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/NameId.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/NameId.java new file mode 100644 index 00000000..94e045d3 --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/NameId.java @@ -0,0 +1,7 @@ +package p.studio.compiler.source.identifiers; + +public class NameId extends AbstractSourceIdentifier { + public NameId(long id) { + super(id); + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/NodeId.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/NodeId.java new file mode 100644 index 00000000..2789b807 --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/NodeId.java @@ -0,0 +1,7 @@ +package p.studio.compiler.source.identifiers; + +public class NodeId extends AbstractSourceIdentifier { + public NodeId(long id) { + super(id); + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/ProjectId.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/ProjectId.java new file mode 100644 index 00000000..b1759645 --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/ProjectId.java @@ -0,0 +1,11 @@ +package p.studio.compiler.source.identifiers; + +public class ProjectId extends AbstractSourceIdentifier { + public ProjectId(int id) { + super(Integer.toUnsignedLong(id)); + } + + public ProjectId(long id) { + super(id); + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/SymbolId.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/SymbolId.java new file mode 100644 index 00000000..ea1d2345 --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/SymbolId.java @@ -0,0 +1,7 @@ +package p.studio.compiler.source.identifiers; + +public class SymbolId extends AbstractSourceIdentifier { + public SymbolId(int id) { + super(id); + } +} diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/TypeId.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/TypeId.java new file mode 100644 index 00000000..33b4433e --- /dev/null +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/source/identifiers/TypeId.java @@ -0,0 +1,7 @@ +package p.studio.compiler.source.identifiers; + +public class TypeId extends AbstractSourceIdentifier { + public TypeId(long id) { + super(id); + } +} diff --git a/prometeu-compiler/prometeu-deps/build.gradle.kts b/prometeu-compiler/prometeu-deps/build.gradle.kts new file mode 100644 index 00000000..8fef694c --- /dev/null +++ b/prometeu-compiler/prometeu-deps/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("gradle.java-library-conventions") +} + +dependencies { + implementation(project(":prometeu-infra")) + implementation(project(":prometeu-compiler:prometeu-compiler-core")) + implementation(project(":prometeu-compiler:prometeu-frontend-registry")) + implementation(libs.jackson.databind) +} \ No newline at end of file diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/exceptions/BuildException.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/exceptions/BuildException.java new file mode 100644 index 00000000..1b3712c8 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/exceptions/BuildException.java @@ -0,0 +1,11 @@ +package p.studio.compiler.exceptions; + +public class BuildException extends RuntimeException { + public BuildException(String message) { + super(message); + } + + public BuildException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/BuildStack.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/BuildStack.java new file mode 100644 index 00000000..cb502dd2 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/BuildStack.java @@ -0,0 +1,9 @@ +package p.studio.compiler.model; + +import p.studio.compiler.source.identifiers.ProjectId; +import p.studio.utilities.structures.ReadOnlyList; + +import java.util.List; + +public record BuildStack(ReadOnlyList projects) { +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/BuildingIssue.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/BuildingIssue.java new file mode 100644 index 00000000..331d3565 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/BuildingIssue.java @@ -0,0 +1,11 @@ +package p.studio.compiler.model; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class BuildingIssue { + private final String message; + private final Throwable exception; +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/DependencyPipelineConfig.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/DependencyPipelineConfig.java new file mode 100644 index 00000000..9cf3eb58 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/DependencyPipelineConfig.java @@ -0,0 +1,10 @@ +package p.studio.compiler.model; + +import java.nio.file.Path; +import java.util.List; + +public record DependencyPipelineConfig( + boolean explain, + Path cacheDir, + List registryDirs) { +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/LoadedFile.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/LoadedFile.java new file mode 100644 index 00000000..ae8bb513 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/LoadedFile.java @@ -0,0 +1,4 @@ +package p.studio.compiler.model; + +public record LoadedFile(String uri, String text) { +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/LoadedSources.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/LoadedSources.java new file mode 100644 index 00000000..750a9ad2 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/LoadedSources.java @@ -0,0 +1,17 @@ +package p.studio.compiler.model; + +import java.util.List; + +/** + * Sources already loaded by dependencies (IO happens in dependencies, not in pipeline). + */ +public record LoadedSources( + /** + * For each project in the stack, a list of files (uri + text). + */ + List perProject +) { + public LoadedSources { + perProject = List.copyOf(perProject); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ProjectDescriptor.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ProjectDescriptor.java new file mode 100644 index 00000000..6696174c --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ProjectDescriptor.java @@ -0,0 +1,21 @@ +package p.studio.compiler.model; + +import lombok.Builder; +import lombok.Getter; +import p.studio.compiler.source.identifiers.ProjectId; +import p.studio.utilities.structures.ReadOnlyList; + +import java.nio.file.Path; +import java.util.List; + +@Builder +@Getter +public class ProjectDescriptor { + private final ProjectId projectId; + private final String name; + private final String version; + private final Path projectDir; + private final ReadOnlyList sourceRoots; + private final String languageId; + private final SourcePolicy sourcePolicy; +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ProjectSources.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ProjectSources.java new file mode 100644 index 00000000..821876d3 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ProjectSources.java @@ -0,0 +1,9 @@ +package p.studio.compiler.model; + +import p.studio.compiler.source.identifiers.ProjectId; +import p.studio.utilities.structures.ReadOnlyList; + +public record ProjectSources( + ProjectId projectId, + ReadOnlyList files) { +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/PrometeuLock.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/PrometeuLock.java new file mode 100644 index 00000000..df6c3713 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/PrometeuLock.java @@ -0,0 +1,47 @@ +package p.studio.compiler.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +import java.util.List; +import java.util.Optional; + +public record PrometeuLock( + long schema, + List mappings) { + + public PrometeuLock { + mappings = mappings != null ? List.copyOf(mappings) : List.of(); + } + + public static PrometeuLock blank() { + return new PrometeuLock(0, List.of()); + } + + public Optional lookupGitLocalDir( + final String url, + final String rev) { + return mappings + .stream() + .filter(m -> m instanceof LockMapping.Git g && g.url().equals(url) && g.rev().equals(rev)) + .map(m -> ((LockMapping.Git) m).localDir()) + .findFirst(); + } + + @JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "kind" + ) + @JsonSubTypes({ + @JsonSubTypes.Type(value = LockMapping.Git.class, name = "git") + }) + public interface LockMapping { + record Git( + String url, + String rev, + @JsonProperty("local-dir") String localDir + ) implements LockMapping {} + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/PrometeuManifest.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/PrometeuManifest.java new file mode 100644 index 00000000..bfcdb053 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/PrometeuManifest.java @@ -0,0 +1,88 @@ +package p.studio.compiler.model; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import p.studio.compiler.FrontendRegistryService; +import p.studio.compiler.exceptions.BuildException; +import p.studio.utilities.structures.ReadOnlyList; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public record PrometeuManifest( + String name, + String version, + String language, + ReadOnlyList dependencies) { + public static PrometeuManifest extract(final Path path, final ObjectMapper mapper) { + try { + final var root = mapper.readTree(path.toFile()); + final var name = text(root, "name"); + final var version = text(root, "version"); + + final var language = Optional + .ofNullable(root.get("language")) + .map(JsonNode::asText) + .orElseGet(() -> FrontendRegistryService.getDefaultFrontendSpec().getLanguageId()); + + final List dependencies = new ArrayList<>(); + final var dependencyNodes = root.get("dependencies"); + if (dependencyNodes != null && dependencyNodes.isArray()) { + for (final var d : dependencyNodes) { + if (d.has("path")) { + dependencies.add(new PrometeuManifest.DependencyDeclaration.Local(d.get("path").asText())); + } else if (d.has("url")) { + final var url = d.get("url").asText(); + final var rev = d.has("rev") ? d.get("rev").asText(null) : null; + dependencies.add(new PrometeuManifest.DependencyDeclaration.Git(url, rev)); + } + } + } + + return new PrometeuManifest(name, version, language, ReadOnlyList.wrap(dependencies)); + } catch (IOException e) { + throw new BuildException("dependencies: failed to read or parse prometeu manifest " + path, e); + } + } + + private static String text(final JsonNode root, final String field) { + JsonNode n = root.get(field); + return n != null ? n.asText() : null; + } + + @JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION) + @JsonSubTypes({ + @JsonSubTypes.Type(value = DependencyDeclaration.Local.class), + @JsonSubTypes.Type(value = DependencyDeclaration.Git.class) + }) + public interface DependencyDeclaration { + @Getter + class Local implements DependencyDeclaration { + private final String path; + + @JsonCreator + public Local(@JsonProperty("path") final String path) { + this.path = path; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + @Getter + class Git implements DependencyDeclaration { + private final String git; + private final String rev; + + @JsonCreator + public Git(@JsonProperty("url") final String git, @JsonProperty("rev") final String rev) { + this.git = git; + this.rev = rev; + } + } + } + +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ResolvedGraph.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ResolvedGraph.java new file mode 100644 index 00000000..659d6f05 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ResolvedGraph.java @@ -0,0 +1,15 @@ +package p.studio.compiler.model; + +import p.studio.compiler.source.identifiers.ProjectId; +import p.studio.utilities.structures.ReadOnlyList; + +import java.util.List; + +public record ResolvedGraph( + ProjectId root, + ReadOnlyList projects, + ReadOnlyList> edges) { + public ProjectDescriptor project(ProjectId id) { + return projects.get(id.getIndex()); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ResolvedWorkspace.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ResolvedWorkspace.java new file mode 100644 index 00000000..427691b0 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/ResolvedWorkspace.java @@ -0,0 +1,9 @@ +package p.studio.compiler.model; + +import p.studio.compiler.source.identifiers.ProjectId; + +public record ResolvedWorkspace( + ProjectId projectId, + ResolvedGraph graph, + BuildStack stack) { +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/SourcePolicy.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/SourcePolicy.java new file mode 100644 index 00000000..ee9bf918 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/model/SourcePolicy.java @@ -0,0 +1,6 @@ +package p.studio.compiler.model; + +import p.studio.utilities.structures.ReadOnlyList; + +public record SourcePolicy(ReadOnlyList extensions, boolean caseSensitive) { +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelineContext.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelineContext.java new file mode 100644 index 00000000..f6f1f4b1 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelineContext.java @@ -0,0 +1,71 @@ +package p.studio.compiler.workspaces; + +import p.studio.compiler.model.*; +import p.studio.compiler.source.identifiers.ProjectId; +import p.studio.compiler.exceptions.BuildException; +import p.studio.utilities.structures.ReadOnlyList; + +import java.nio.file.Path; +import java.util.*; + +public final class DependencyPipelineContext { + private final DependencyPipelineConfig config; + + // Internal state mirroring Rust ResolverState + public Path mainProjectRootPathCanon; + + // Phase 1 (Discover) + public final List projectInfos = new ArrayList<>(); + public final Map projectIndexByDirectory = new HashMap<>(); + public final Deque pending = new ArrayDeque<>(); + + // Phase 2+ + public final List projectNodes = new ArrayList<>(); + public final Map projectIdByDirectoryRoot = new HashMap<>(); + public final List> dependenciesByProject = new ArrayList<>(); + + public ProjectId root; + public BuildStack stack; + + private DependencyPipelineContext(DependencyPipelineConfig config) { + this.config = config; + } + + public static DependencyPipelineContext seed(DependencyPipelineConfig config) { + return new DependencyPipelineContext(config); + } + + public DependencyPipelineConfig config() { + return config; + } + + public ResolvedWorkspace toResolvedWorkspace() { + if (root == null) { + throw new BuildException("dependencies: internal error: root ProjectId not set"); + } + final var projectDescriptors = ReadOnlyList.wrap(projectNodes + .stream() + .map(n -> { + final var languageId = n.getLanguageId(); + final var sourcePolicy = new SourcePolicy(ReadOnlyList.empty(), true); // TODO: source policy should come from a frontend registry anginst language id + return ProjectDescriptor + .builder() + .projectId(n.getProjectId()) + .name(n.getName()) + .version(n.getVersion()) + .projectDir(n.getProjectRootPath()) + .sourceRoots(n.getSourceRoots()) + .languageId(languageId) + .sourcePolicy(sourcePolicy) + .build(); + }) + .toList()); + final var edges = ReadOnlyList.wrap(this + .dependenciesByProject + .stream() + .map(ReadOnlyList::wrap) + .toList()); + final var graph = new ResolvedGraph(root, projectDescriptors, edges); + return new ResolvedWorkspace(root, graph, stack); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelinePhase.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelinePhase.java new file mode 100644 index 00000000..d14ce66e --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelinePhase.java @@ -0,0 +1,8 @@ +package p.studio.compiler.workspaces; + +import p.studio.compiler.model.BuildingIssue; +import p.studio.utilities.structures.ReadOnlyCollection; + +public interface DependencyPipelinePhase { + ReadOnlyCollection run(DependencyPipelineContext state); +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelineService.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelineService.java new file mode 100644 index 00000000..d46fc2fe --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyPipelineService.java @@ -0,0 +1,36 @@ +package p.studio.compiler.workspaces; + +import lombok.extern.slf4j.Slf4j; +import p.studio.compiler.exceptions.BuildException; +import p.studio.compiler.model.DependencyPipelineConfig; +import p.studio.compiler.model.ResolvedWorkspace; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.util.List; + +@Slf4j +public final class DependencyPipelineService { + private final List phases; + + public DependencyPipelineService(List phases) { + this.phases = phases; + } + + public ResolvedWorkspace run(DependencyPipelineConfig config) { + final var ctx = DependencyPipelineContext.seed(config); + + for (final var dependencyPipelinePhase : phases) { + final var issues = dependencyPipelinePhase.run(ctx); + if (ReadOnlyCollection.isNotEmpty(issues)) { + for (final var issue : issues) { + log.error(issue.getMessage(), issue.getException()); + } + throw new BuildException("issues found during dependency pipeline phase: " + dependencyPipelinePhase.getClass().getSimpleName()); + } + } + + log.info("dependency pipeline completed successfully, going to resolve workspace"); + + return ctx.toResolvedWorkspace(); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyReference.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyReference.java new file mode 100644 index 00000000..86013041 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyReference.java @@ -0,0 +1,6 @@ +package p.studio.compiler.workspaces; + +import java.nio.file.Path; + +public record DependencyReference(Path path) { +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/ProjectInfo.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/ProjectInfo.java new file mode 100644 index 00000000..982973ea --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/ProjectInfo.java @@ -0,0 +1,16 @@ +package p.studio.compiler.workspaces; + +import lombok.Builder; +import lombok.Getter; +import p.studio.compiler.model.FrontendSpec; +import p.studio.compiler.model.PrometeuManifest; +import java.nio.file.Path; + +@Builder +@Getter +public final class ProjectInfo { + public final Path rootDirectory; + public final Path manifestPath; + public final PrometeuManifest manifest; + public final FrontendSpec frontendSpec; +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/ProjectNode.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/ProjectNode.java new file mode 100644 index 00000000..35df4b53 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/ProjectNode.java @@ -0,0 +1,22 @@ +package p.studio.compiler.workspaces; + +import lombok.Builder; +import lombok.Getter; +import p.studio.compiler.model.FrontendSpec; +import p.studio.compiler.source.identifiers.ProjectId; +import p.studio.utilities.structures.ReadOnlyList; + +import java.nio.file.Path; + +@Builder +@Getter +public final class ProjectNode { + private final FrontendSpec frontendSpec; + private final ProjectId projectId; + private final Path projectRootPath; + private final String name; + private final String version; + private final ReadOnlyList sourceRoots; + private final String languageId; + private final ReadOnlyList dependencies; +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/DiscoverPhase.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/DiscoverPhase.java new file mode 100644 index 00000000..28ba889d --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/DiscoverPhase.java @@ -0,0 +1,94 @@ +package p.studio.compiler.workspaces.phases; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import p.studio.compiler.FrontendRegistryService; +import p.studio.compiler.model.BuildingIssue; +import p.studio.compiler.model.PrometeuManifest; +import p.studio.compiler.workspaces.DependencyPipelinePhase; +import p.studio.compiler.workspaces.DependencyPipelineContext; +import p.studio.compiler.workspaces.ProjectInfo; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public class DiscoverPhase implements DependencyPipelinePhase { + private final ObjectMapper mapper = new ObjectMapper(); + + @Override + public ReadOnlyCollection run(final DependencyPipelineContext ctx) { + final List issues = new ArrayList<>(); + while (!ctx.pending.isEmpty()) { + final var rootPathCanon = ctx.pending.pollFirst(); + + if (ctx.projectIndexByDirectory.containsKey(rootPathCanon)) { + continue; + } + + final var manifestPath = rootPathCanon.resolve("prometeu.json"); + if (!Files.exists(manifestPath) || !Files.isRegularFile(manifestPath)) { + final var issue = BuildingIssue + .builder() + .message("dependencies: manifest not found: expected a file " + manifestPath + " (" + rootPathCanon + ")") + .build(); + issues.add(issue); + continue; + } + + final var manifest = PrometeuManifest.extract(manifestPath, mapper); + + final var frontendSpec = FrontendRegistryService.getFrontendSpec(manifest.language()); + if (frontendSpec.isEmpty()) { + final var issue = BuildingIssue + .builder() + .message("dependencies: unknown language " + manifest.language() + " for project " + manifest.name()) + .build(); + issues.add(issue); + continue; + } + if (ReadOnlyCollection.isEmpty(manifest.dependencies())) { + log.warn("dependencies: no dependencies specified for project {}", manifest.name()); + } + + final long projectIndex = ctx.projectInfos.size(); + final var projectInfo = ProjectInfo + .builder() + .rootDirectory(rootPathCanon) + .manifestPath(manifestPath) + .manifest(manifest) + .frontendSpec(frontendSpec.get()) + .build(); + ctx.projectInfos.add(projectInfo); + ctx.projectIndexByDirectory.put(rootPathCanon, projectIndex); + + for (final var dependencyDeclaration : manifest.dependencies()) { + if (dependencyDeclaration instanceof PrometeuManifest.DependencyDeclaration.Local local) { + final var dependencyPath = rootPathCanon.resolve(local.getPath()); + try { + final var dependencyPathCanon = dependencyPath.toRealPath(); + ctx.pending.add(dependencyPathCanon); + } catch (IOException e) { + final var issue = BuildingIssue + .builder() + .message("dependencies: dep path does not exist: " + dependencyPath + " (" + rootPathCanon + ")") + .exception(e) + .build(); + issues.add(issue); + } + } else if (dependencyDeclaration instanceof PrometeuManifest.DependencyDeclaration.Git) { + final var issue = BuildingIssue + .builder() + .message("dependencies: url dependencies not yet supported " + manifest.name() + " (" + rootPathCanon + ")") + .build(); + issues.add(issue); + } + } + } + + return ReadOnlyCollection.wrap(issues); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/LocalizePhase.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/LocalizePhase.java new file mode 100644 index 00000000..cd8d9242 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/LocalizePhase.java @@ -0,0 +1,33 @@ +package p.studio.compiler.workspaces.phases; + +import p.studio.compiler.model.BuildingIssue; +import p.studio.compiler.workspaces.*; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public final class LocalizePhase implements DependencyPipelinePhase { + @Override + public ReadOnlyCollection run(final DependencyPipelineContext state) { + final List issues = new ArrayList<>(); + for (int i = 0; i < state.projectNodes.size(); i++) { + final var fromProjectNode = state.projectNodes.get(i); + for (final var dependencyReference : fromProjectNode.getDependencies()) { + final var dependencyReferencePath = dependencyReference.path(); + final var projectId = state.projectIdByDirectoryRoot.get(dependencyReferencePath); + if (Objects.isNull(projectId)) { + final var issue = BuildingIssue + .builder() + .message("dependencies: dependency not found: " + dependencyReferencePath + " (referenced from " + fromProjectNode.getProjectRootPath() + ")") + .build(); + issues.add(issue); + continue; + } + state.dependenciesByProject.get(fromProjectNode.getProjectId().getIndex()).add(projectId); + } + } + return ReadOnlyCollection.wrap(issues); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/MaterializePhase.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/MaterializePhase.java new file mode 100644 index 00000000..8394bbd9 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/MaterializePhase.java @@ -0,0 +1,106 @@ +package p.studio.compiler.workspaces.phases; + +import p.studio.compiler.model.BuildingIssue; +import p.studio.compiler.model.PrometeuManifest; +import p.studio.compiler.source.identifiers.ProjectId; +import p.studio.compiler.workspaces.*; +import p.studio.utilities.structures.ReadOnlyCollection; +import p.studio.utilities.structures.ReadOnlyList; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.*; + +public final class MaterializePhase implements DependencyPipelinePhase { + @Override + public ReadOnlyCollection run(final DependencyPipelineContext ctx) { + // start all over again, we will re-populate the project nodes and edges based on the project infos + ctx.projectNodes.clear(); + ctx.projectIdByDirectoryRoot.clear(); + ctx.dependenciesByProject.clear(); + ctx.root = null; + + final List issues = new ArrayList<>(); + for (int index = 0; index < ctx.projectInfos.size(); index++) { + final var projectId = new ProjectId(index); + final var projectInfo = ctx.projectInfos.get(index); + ctx.projectNodes.add(buildProjectNode(projectId, projectInfo, issues)); + ctx.projectIdByDirectoryRoot.put(projectInfo.rootDirectory, projectId); + ctx.dependenciesByProject.add(new ArrayList<>()); + } + + final var rootProjectId = ctx.projectIdByDirectoryRoot.get(ctx.mainProjectRootPathCanon); + if (rootProjectId == null) { + final var issue = BuildingIssue + .builder() + .message("dependencies: root project dir " + ctx.mainProjectRootPathCanon + " was not discovered/materialized") + .build(); + issues.add(issue); + return ReadOnlyCollection.wrap(issues); + } + ctx.root = rootProjectId; + + return ReadOnlyCollection.wrap(issues); + } + + private static ProjectNode buildProjectNode( + final ProjectId projectId, + final ProjectInfo projectInfo, + final List issues) { + final List sourceRootIssues = new ArrayList<>(); + final List sourceRoots = new ArrayList<>(); + for (final var sourceRoot : projectInfo.getFrontendSpec().getSourceRoots()) { + final var sourceRootPath = projectInfo.rootDirectory.resolve(sourceRoot); + try { + final var sourceRootPathCanon = sourceRootPath.toRealPath(); + sourceRoots.add(sourceRootPathCanon); + } catch (IOException e) { + final var issue = BuildingIssue + .builder() + .message("dependencies: source root path does not exist: " + sourceRootPath + " (from " + projectInfo.rootDirectory + ")") + .exception(e) + .build(); + sourceRootIssues.add(issue); + } + } + if (sourceRootIssues.size() == projectInfo.getFrontendSpec().getSourceRoots().size()) { + // no source roots were found at all + issues.addAll(sourceRootIssues); + } + + final List dependencyReferencies = new ArrayList<>(); + for (PrometeuManifest.DependencyDeclaration d : projectInfo.manifest.dependencies()) { + if (d instanceof PrometeuManifest.DependencyDeclaration.Local l) { + final var dependencyPath = projectInfo.rootDirectory.resolve(l.getPath()); + try { + final var dependencyPathCanon = dependencyPath.toRealPath(); + dependencyReferencies.add(new DependencyReference(dependencyPathCanon)); + } catch (IOException e) { + final var issue = BuildingIssue + .builder() + .message("dependencies: local dep path does not exist: " + dependencyPath + " (from " + projectInfo.rootDirectory + ")") + .exception(e) + .build(); + issues.add(issue); + } + } else if (d instanceof PrometeuManifest.DependencyDeclaration.Git g) { + final var issue = BuildingIssue + .builder() + .message("dependencies: url dependency '" + g.getGit() + "' requires an explicit 'rev' and lock mapping (not supported yet)") + .build(); + issues.add(issue); + } + } + + return ProjectNode + .builder() + .projectId(projectId) + .projectRootPath(projectInfo.rootDirectory) + .name(projectInfo.manifest.name()) + .version(projectInfo.manifest.version()) + .languageId(projectInfo.manifest.language()) + .sourceRoots(ReadOnlyList.wrap(sourceRoots)) + .dependencies(ReadOnlyList.wrap(dependencyReferencies)) + .build(); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/PolicyPhase.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/PolicyPhase.java new file mode 100644 index 00000000..4f1d74fe --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/PolicyPhase.java @@ -0,0 +1,18 @@ +package p.studio.compiler.workspaces.phases; + +import p.studio.compiler.model.BuildingIssue; +import p.studio.compiler.workspaces.DependencyPipelinePhase; +import p.studio.compiler.workspaces.DependencyPipelineContext; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.util.ArrayList; +import java.util.List; + +public final class PolicyPhase implements DependencyPipelinePhase { + @Override + public ReadOnlyCollection run(DependencyPipelineContext state) { + final List issues = new ArrayList<>(); + // No-op for now; in Rust this applies source policies + return ReadOnlyCollection.wrap(issues); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/SeedPhase.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/SeedPhase.java new file mode 100644 index 00000000..3e9a3027 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/SeedPhase.java @@ -0,0 +1,29 @@ +package p.studio.compiler.workspaces.phases; + +import p.studio.compiler.model.BuildingIssue; +import p.studio.compiler.workspaces.DependencyPipelinePhase; +import p.studio.compiler.workspaces.DependencyPipelineContext; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public final class SeedPhase implements DependencyPipelinePhase { + @Override + public ReadOnlyCollection run(final DependencyPipelineContext ctx) { + final List issues = new ArrayList<>(); + try { + ctx.mainProjectRootPathCanon = ctx.config().cacheDir().toRealPath(); + } catch (IOException e) { + final var issue = BuildingIssue + .builder() + .message("Failed to canonicalize root directory: " + ctx.config().cacheDir()) + .build(); + issues.add(issue); + } + ctx.pending.add(ctx.mainProjectRootPathCanon); + + return ReadOnlyCollection.wrap(issues); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/StackPhase.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/StackPhase.java new file mode 100644 index 00000000..bf08d008 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/StackPhase.java @@ -0,0 +1,61 @@ +package p.studio.compiler.workspaces.phases; + +import p.studio.compiler.model.BuildStack; +import p.studio.compiler.model.BuildingIssue; +import p.studio.compiler.source.identifiers.ProjectId; +import p.studio.compiler.workspaces.DependencyPipelineContext; +import p.studio.compiler.workspaces.DependencyPipelinePhase; +import p.studio.utilities.structures.ReadOnlyCollection; +import p.studio.utilities.structures.ReadOnlyList; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +public final class StackPhase implements DependencyPipelinePhase { + /** + * Implements topological sort; detects dependency cycles; sets build stack + */ + @Override + public ReadOnlyCollection run(DependencyPipelineContext state) { + final List issues = new ArrayList<>(); + + final int n = state.projectNodes.size(); + final int[] indeg = new int[n]; + for (int from = 0; from < n; from++) { + for (final ProjectId to : state.dependenciesByProject.get(from)) { + indeg[to.getIndex()]++; + } + } + + final Deque q = new ArrayDeque<>(); + for (int i = 0; i < n; i++) { + if (indeg[i] == 0) q.add(i); + } + + final List travesalOrder = new ArrayList<>(n); + // Performs topological sort using Kahn's algorithm + while (!q.isEmpty()) { + final int u = q.removeFirst(); + travesalOrder.add(state.projectNodes.get(u).getProjectId()); + for (final ProjectId v : state.dependenciesByProject.get(u)) { + if (--indeg[(int) v.getId()] == 0) { + q.addLast((int) v.getId()); + } + } + } + + if (travesalOrder.size() != n) { + issues.add(BuildingIssue + .builder() + .message("dependencies: cycle detected in dependency graph") + .build()); + return ReadOnlyCollection.wrap(issues); + } + + state.stack = new BuildStack(ReadOnlyList.wrap(travesalOrder)); + + return ReadOnlyCollection.wrap(issues); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/ValidatePhase.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/ValidatePhase.java new file mode 100644 index 00000000..14e39fe3 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/ValidatePhase.java @@ -0,0 +1,30 @@ +package p.studio.compiler.workspaces.phases; + +import p.studio.compiler.model.BuildingIssue; +import p.studio.compiler.workspaces.*; +import p.studio.compiler.exceptions.BuildException; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.util.ArrayList; +import java.util.List; + +public final class ValidatePhase implements DependencyPipelinePhase { + @Override + public ReadOnlyCollection run(DependencyPipelineContext state) { + final List issues = new ArrayList<>(); + if (state.root == null) { + issues.add(BuildingIssue + .builder() + .message("dependencies: root ProjectId not set") + .build()); + return ReadOnlyCollection.wrap(issues); + } + + // Ensure edges list matches number of nodes + if (state.dependenciesByProject.size() != state.projectNodes.size()) { + throw new BuildException("dependencies: internal error: edges list size mismatch"); + } + + return ReadOnlyCollection.wrap(issues); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/DependencyPipelineServiceTest.java b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/DependencyPipelineServiceTest.java new file mode 100644 index 00000000..7db0418f --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/DependencyPipelineServiceTest.java @@ -0,0 +1,77 @@ +package p.studio.compiler.workspaces; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import p.studio.compiler.exceptions.BuildException; +import p.studio.compiler.model.DependencyPipelineConfig; +import p.studio.compiler.model.ResolvedWorkspace; +import p.studio.compiler.workspaces.phases.*; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class DependencyPipelineServiceTest { + + @Test + void canonical_pipeline_e2e(@TempDir Path tempDir) throws IOException { + final Path root = tempDir; + final Path depA = root.resolve("depA"); + Files.createDirectories(depA); + Files.createDirectories(root.resolve("src")); + Files.createDirectories(depA.resolve("src")); + + writeManifest(root, "root-proj", "0.1.0", new String[]{"depA"}); + writeManifest(depA, "dep-a", "0.1.0", new String[]{}); + + final var cfg = new DependencyPipelineConfig(false, root, List.of()); + final var phases = List.of( + new SeedPhase(), + new DiscoverPhase(), + new MaterializePhase(), + new LocalizePhase(), + new ValidatePhase(), + new StackPhase(), + new PolicyPhase() + ); + + final var service = new DependencyPipelineService(phases); + final ResolvedWorkspace ws = service.run(cfg); + + assertNotNull(ws); + assertNotNull(ws.graph()); + assertEquals(2, ws.graph().projects().size()); + + // Obter ids por nome + var rootDesc = ws.graph().projects().stream().filter(p -> p.getName().equals("root-proj")).findFirst().orElseThrow(); + var depDesc = ws.graph().projects().stream().filter(p -> p.getName().equals("dep-a")).findFirst().orElseThrow(); + final var rootId = rootDesc.getProjectId(); + final var depId = depDesc.getProjectId(); + + // Edges: root -> dep + assertTrue(ws.graph().edges().get(rootId.getIndex()).contains(depId)); + assertTrue(ws.graph().edges().get(depId.getIndex()).isEmpty()); + + // Stack: de acordo com a implementação atual (arestas root->dep), root vem antes + assertEquals(rootId, ws.stack().projects().get(0)); + assertEquals(depId, ws.stack().projects().get(1)); + + // workspace.root é o projeto root + assertEquals(rootId, ws.projectId()); + } + + private static void writeManifest(Path dir, String name, String version, String[] localDeps) throws IOException { + final StringBuilder deps = new StringBuilder(); + deps.append("["); + for (int i = 0; i < localDeps.length; i++) { + if (i > 0) deps.append(","); + deps.append("{\"path\":\"").append(localDeps[i]).append("\"}"); + } + deps.append("]"); + final String json = "{\n \"name\": \"" + name + "\",\n \"version\": \"" + version + "\",\n \"dependencies\": " + deps + "\n}"; + Files.writeString(dir.resolve("prometeu.json"), json); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/DiscoverPhaseTest.java b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/DiscoverPhaseTest.java new file mode 100644 index 00000000..857452c7 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/DiscoverPhaseTest.java @@ -0,0 +1,54 @@ +package p.studio.compiler.workspaces; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import p.studio.compiler.model.DependencyPipelineConfig; +import p.studio.compiler.workspaces.phases.DiscoverPhase; +import p.studio.compiler.workspaces.phases.SeedPhase; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; + +class DiscoverPhaseTest { + + @Test + void discover_finds_root_and_local_dependency(@TempDir Path tempDir) throws IOException { + // Estrutura: root/ (prometeu.json) -> deps: ["depA/"] e cria depA/(prometeu.json) + final Path root = tempDir; + final Path depA = root.resolve("depA"); + Files.createDirectories(depA); + + writeManifest(root, "root-proj", "0.1.0", new String[]{"depA"}, null); + writeManifest(depA, "dep-a", "0.1.0", new String[]{}, null); + + final var cfg = new DependencyPipelineConfig(false, root, java.util.List.of()); + final var ctx = DependencyPipelineContext.seed(cfg); + assertTrue(ReadOnlyCollection.isEmpty(new SeedPhase().run(ctx))); + + final var issues = new DiscoverPhase().run(ctx); + assertTrue(ReadOnlyCollection.isEmpty(issues), "Descoberta deve ocorrer sem issues"); + + assertEquals(2, ctx.projectInfos.size(), "Dois projetos devem ser descobertos"); + assertTrue(ctx.projectIndexByDirectory.containsKey(root.toRealPath()), "Projeto raiz indexado"); + assertTrue(ctx.projectIndexByDirectory.containsKey(depA.toRealPath()), "Projeto depA indexado"); + assertEquals(0L, ctx.projectIndexByDirectory.get(root.toRealPath())); + assertEquals(1L, ctx.projectIndexByDirectory.get(depA.toRealPath())); + } + + private static void writeManifest(Path dir, String name, String version, String[] localDeps, String language) throws IOException { + final StringBuilder deps = new StringBuilder(); + deps.append("["); + for (int i = 0; i < localDeps.length; i++) { + if (i > 0) deps.append(","); + deps.append("{\"path\":\"").append(localDeps[i]).append("\"}"); + } + deps.append("]"); + final String langField = language == null ? "" : ",\n \"language\": \"" + language + "\""; + final String json = "{\n \"name\": \"" + name + "\",\n \"version\": \"" + version + "\",\n \"dependencies\": " + deps + langField + "\n}"; + Files.writeString(dir.resolve("prometeu.json"), json); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/LocalizePhaseTest.java b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/LocalizePhaseTest.java new file mode 100644 index 00000000..eb69c120 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/LocalizePhaseTest.java @@ -0,0 +1,54 @@ +package p.studio.compiler.workspaces; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import p.studio.compiler.model.DependencyPipelineConfig; +import p.studio.compiler.workspaces.phases.*; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; + +class LocalizePhaseTest { + + @Test + void localize_resolves_dependency_references(@TempDir Path tempDir) throws IOException { + final Path root = tempDir; + final Path depA = root.resolve("depA"); + Files.createDirectories(depA); + Files.createDirectories(root.resolve("src")); + Files.createDirectories(depA.resolve("src")); + + writeManifest(root, "root-proj", "0.1.0", new String[]{"depA"}); + writeManifest(depA, "dep-a", "0.1.0", new String[]{}); + + final var cfg = new DependencyPipelineConfig(false, root, java.util.List.of()); + final var ctx = DependencyPipelineContext.seed(cfg); + assertTrue(ReadOnlyCollection.isEmpty(new SeedPhase().run(ctx))); + assertTrue(ReadOnlyCollection.isEmpty(new DiscoverPhase().run(ctx))); + assertTrue(ReadOnlyCollection.isEmpty(new MaterializePhase().run(ctx))); + + final var issues = new LocalizePhase().run(ctx); + assertTrue(ReadOnlyCollection.isEmpty(issues), "Localização deve ocorrer sem issues"); + + final var depId = ctx.projectIdByDirectoryRoot.get(depA.toRealPath()); + assertNotNull(depId); + final var rootId = ctx.root; + assertTrue(ctx.dependenciesByProject.get(rootId.getIndex()).contains(depId), "Root deve depender de depA"); + } + + private static void writeManifest(Path dir, String name, String version, String[] localDeps) throws IOException { + final StringBuilder deps = new StringBuilder(); + deps.append("["); + for (int i = 0; i < localDeps.length; i++) { + if (i > 0) deps.append(","); + deps.append("{\"path\":\"").append(localDeps[i]).append("\"}"); + } + deps.append("]"); + final String json = "{\n \"name\": \"" + name + "\",\n \"version\": \"" + version + "\",\n \"dependencies\": " + deps + "\n}"; + Files.writeString(dir.resolve("prometeu.json"), json); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/MaterializePhaseTest.java b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/MaterializePhaseTest.java new file mode 100644 index 00000000..9c827e27 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/MaterializePhaseTest.java @@ -0,0 +1,62 @@ +package p.studio.compiler.workspaces; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import p.studio.compiler.model.DependencyPipelineConfig; +import p.studio.compiler.workspaces.phases.DiscoverPhase; +import p.studio.compiler.workspaces.phases.MaterializePhase; +import p.studio.compiler.workspaces.phases.SeedPhase; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; + +class MaterializePhaseTest { + + @Test + void materialize_builds_nodes_and_sets_root(@TempDir Path tempDir) throws IOException { + final Path root = tempDir; + final Path depA = root.resolve("depA"); + Files.createDirectories(depA); + Files.createDirectories(root.resolve("src")); + Files.createDirectories(depA.resolve("src")); + + writeManifest(root, "root-proj", "0.1.0", new String[]{"depA"}); + writeManifest(depA, "dep-a", "0.1.0", new String[]{}); + + final var cfg = new DependencyPipelineConfig(false, root, java.util.List.of()); + final var ctx = DependencyPipelineContext.seed(cfg); + assertTrue(ReadOnlyCollection.isEmpty(new SeedPhase().run(ctx))); + assertTrue(ReadOnlyCollection.isEmpty(new DiscoverPhase().run(ctx))); + + final var issues = new MaterializePhase().run(ctx); + assertTrue(ReadOnlyCollection.isEmpty(issues), "Materialização sem issues esperadas"); + + assertNotNull(ctx.root, "Root ProjectId deve ser definido"); + assertEquals(2, ctx.projectNodes.size()); + assertEquals(2, ctx.dependenciesByProject.size()); + assertTrue(ctx.projectIdByDirectoryRoot.containsKey(root.toRealPath())); + assertTrue(ctx.projectIdByDirectoryRoot.containsKey(depA.toRealPath())); + + final var rootNode = ctx.projectNodes.get(ctx.root.getIndex()); + assertEquals("root-proj", rootNode.getName()); + assertEquals("0.1.0", rootNode.getVersion()); + assertEquals("pbs", rootNode.getLanguageId()); + assertFalse(rootNode.getSourceRoots().isEmpty(), "Deve haver pelo menos um source root (src)"); + } + + private static void writeManifest(Path dir, String name, String version, String[] localDeps) throws IOException { + final StringBuilder deps = new StringBuilder(); + deps.append("["); + for (int i = 0; i < localDeps.length; i++) { + if (i > 0) deps.append(","); + deps.append("{\"path\":\"").append(localDeps[i]).append("\"}"); + } + deps.append("]"); + final String json = "{\n \"name\": \"" + name + "\",\n \"version\": \"" + version + "\",\n \"dependencies\": " + deps + "\n}"; + Files.writeString(dir.resolve("prometeu.json"), json); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/SeedPhaseTest.java b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/SeedPhaseTest.java new file mode 100644 index 00000000..c70136a6 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/SeedPhaseTest.java @@ -0,0 +1,27 @@ +package p.studio.compiler.workspaces; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import p.studio.compiler.model.DependencyPipelineConfig; +import p.studio.compiler.workspaces.phases.SeedPhase; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; + +class SeedPhaseTest { + + @Test + void seed_initializes_root_and_pending(@TempDir Path tempDir) throws Exception { + final var cfg = new DependencyPipelineConfig(false, tempDir, java.util.List.of()); + final var ctx = DependencyPipelineContext.seed(cfg); + + final var issues = new SeedPhase().run(ctx); + assertTrue(ReadOnlyCollection.isEmpty(issues), "Nenhum issue esperado na SeedPhase"); + + assertNotNull(ctx.mainProjectRootPathCanon, "Caminho canônico do projeto raiz deve ser inicializado"); + assertEquals(1, ctx.pending.size(), "Uma entrada deve ser enfileirada para descoberta inicial"); + assertEquals(tempDir.toRealPath(), ctx.mainProjectRootPathCanon); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/StackPhaseTest.java b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/StackPhaseTest.java new file mode 100644 index 00000000..193cf8bc --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/StackPhaseTest.java @@ -0,0 +1,57 @@ +package p.studio.compiler.workspaces; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import p.studio.compiler.model.DependencyPipelineConfig; +import p.studio.compiler.workspaces.phases.*; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; + +class StackPhaseTest { + + @Test + void stack_topologically_sorts_projects(@TempDir Path tempDir) throws IOException { + final Path root = tempDir; + final Path depA = root.resolve("depA"); + Files.createDirectories(depA); + Files.createDirectories(root.resolve("src")); + Files.createDirectories(depA.resolve("src")); + + writeManifest(root, "root-proj", "0.1.0", new String[]{"depA"}); + writeManifest(depA, "dep-a", "0.1.0", new String[]{}); + + final var cfg = new DependencyPipelineConfig(false, root, java.util.List.of()); + final var ctx = DependencyPipelineContext.seed(cfg); + assertTrue(ReadOnlyCollection.isEmpty(new SeedPhase().run(ctx))); + assertTrue(ReadOnlyCollection.isEmpty(new DiscoverPhase().run(ctx))); + assertTrue(ReadOnlyCollection.isEmpty(new MaterializePhase().run(ctx))); + assertTrue(ReadOnlyCollection.isEmpty(new LocalizePhase().run(ctx))); + + final var issues = new StackPhase().run(ctx); + assertTrue(ReadOnlyCollection.isEmpty(issues), "Ordenação sem issues"); + + assertNotNull(ctx.stack); + assertEquals(2, ctx.stack.projects().size()); + final var depId = ctx.projectIdByDirectoryRoot.get(depA.toRealPath()); + final var rootId = ctx.root; + assertEquals(rootId, ctx.stack.projects().get(0), "Root (sem entradas) vem primeiro pelo algoritmo atual"); + assertEquals(depId, ctx.stack.projects().get(1)); + } + + private static void writeManifest(Path dir, String name, String version, String[] localDeps) throws IOException { + final StringBuilder deps = new StringBuilder(); + deps.append("["); + for (int i = 0; i < localDeps.length; i++) { + if (i > 0) deps.append(","); + deps.append("{\"path\":\"").append(localDeps[i]).append("\"}"); + } + deps.append("]"); + final String json = "{\n \"name\": \"" + name + "\",\n \"version\": \"" + version + "\",\n \"dependencies\": " + deps + "\n}"; + Files.writeString(dir.resolve("prometeu.json"), json); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/ValidateAndPolicyPhasesTest.java b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/ValidateAndPolicyPhasesTest.java new file mode 100644 index 00000000..edcdced2 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/test/java/p/studio/compiler/workspaces/ValidateAndPolicyPhasesTest.java @@ -0,0 +1,58 @@ +package p.studio.compiler.workspaces; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import p.studio.compiler.model.DependencyPipelineConfig; +import p.studio.compiler.workspaces.phases.*; +import p.studio.utilities.structures.ReadOnlyCollection; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; + +class ValidateAndPolicyPhasesTest { + + @Test + void validate_checks_consistency_without_issues(@TempDir Path tempDir) throws IOException { + final Path root = tempDir; + final Path depA = root.resolve("depA"); + Files.createDirectories(depA); + Files.createDirectories(root.resolve("src")); + Files.createDirectories(depA.resolve("src")); + + writeManifest(root, "root-proj", "0.1.0", new String[]{"depA"}); + writeManifest(depA, "dep-a", "0.1.0", new String[]{}); + + final var cfg = new DependencyPipelineConfig(false, root, java.util.List.of()); + final var ctx = DependencyPipelineContext.seed(cfg); + assertTrue(ReadOnlyCollection.isEmpty(new SeedPhase().run(ctx))); + assertTrue(ReadOnlyCollection.isEmpty(new DiscoverPhase().run(ctx))); + assertTrue(ReadOnlyCollection.isEmpty(new MaterializePhase().run(ctx))); + assertTrue(ReadOnlyCollection.isEmpty(new LocalizePhase().run(ctx))); + + final var issues = new ValidatePhase().run(ctx); + assertTrue(ReadOnlyCollection.isEmpty(issues), "Validação não deve reportar issues no cenário feliz"); + } + + @Test + void policy_is_noop(@TempDir Path tempDir) { + final var cfg = new DependencyPipelineConfig(false, tempDir, java.util.List.of()); + final var ctx = DependencyPipelineContext.seed(cfg); + final var issues = new PolicyPhase().run(ctx); + assertTrue(ReadOnlyCollection.isEmpty(issues), "PolicyPhase atualmente é no-op"); + } + + private static void writeManifest(Path dir, String name, String version, String[] localDeps) throws IOException { + final StringBuilder deps = new StringBuilder(); + deps.append("["); + for (int i = 0; i < localDeps.length; i++) { + if (i > 0) deps.append(","); + deps.append("{\"path\":\"").append(localDeps[i]).append("\"}"); + } + deps.append("]"); + final String json = "{\n \"name\": \"" + name + "\",\n \"version\": \"" + version + "\",\n \"dependencies\": " + deps + "\n}"; + Files.writeString(dir.resolve("prometeu.json"), json); + } +} diff --git a/prometeu-compiler/prometeu-frontend-api/build.gradle.kts b/prometeu-compiler/prometeu-frontend-api/build.gradle.kts new file mode 100644 index 00000000..8874f7a8 --- /dev/null +++ b/prometeu-compiler/prometeu-frontend-api/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("gradle.java-library-conventions") +} + +dependencies { + api(project(":prometeu-infra")) +} \ No newline at end of file diff --git a/prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/FrontendRegistryService.java b/prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/FrontendRegistryService.java new file mode 100644 index 00000000..82c55762 --- /dev/null +++ b/prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/FrontendRegistryService.java @@ -0,0 +1,4 @@ +package p.studio.compiler; + +public class FrontendRegistryService { +} diff --git a/prometeu-compiler/prometeu-frontend-registry/build.gradle.kts b/prometeu-compiler/prometeu-frontend-registry/build.gradle.kts new file mode 100644 index 00000000..f4af920a --- /dev/null +++ b/prometeu-compiler/prometeu-frontend-registry/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("gradle.java-library-conventions") +} + +dependencies { + implementation(project(":prometeu-infra")) + implementation(project(":prometeu-compiler:prometeu-compiler-core")) + + implementation(project(":prometeu-compiler:frontends:prometeu-frontend-pbs")) +} \ No newline at end of file diff --git a/prometeu-compiler/prometeu-frontend-registry/src/main/java/p/studio/compiler/FrontendRegistryService.java b/prometeu-compiler/prometeu-frontend-registry/src/main/java/p/studio/compiler/FrontendRegistryService.java new file mode 100644 index 00000000..09f100f5 --- /dev/null +++ b/prometeu-compiler/prometeu-frontend-registry/src/main/java/p/studio/compiler/FrontendRegistryService.java @@ -0,0 +1,30 @@ +package p.studio.compiler; + +import p.studio.compiler.model.FrontendSpec; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class FrontendRegistryService { + private static final FrontendSpec[] FRONTEND_SPECS = { + PBSDefinitions.PBS, + }; + + private static final Map FRONTENDS = new HashMap<>(); + + static { + for (final var frontendSpec : FRONTEND_SPECS) { + FRONTENDS.put(frontendSpec.getLanguageId(), frontendSpec); + } + if (FRONTENDS.size() != FRONTEND_SPECS.length) throw new IllegalStateException("Duplicate frontend specs found"); + } + + public static FrontendSpec getDefaultFrontendSpec() { + return FRONTENDS.get(PBSDefinitions.PBS.getLanguageId()); + } + + public static Optional getFrontendSpec(final String languageId) { + return Optional.ofNullable(FRONTENDS.get(languageId)); + } +} diff --git a/prometeu-infra/build.gradle.kts b/prometeu-infra/build.gradle.kts index 83c581d8..0255beb2 100644 --- a/prometeu-infra/build.gradle.kts +++ b/prometeu-infra/build.gradle.kts @@ -3,4 +3,6 @@ plugins { } dependencies { + api(libs.jackson.databind) + api(libs.apache.commons.collections) } \ No newline at end of file diff --git a/prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlyCollection.java b/prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlyCollection.java new file mode 100644 index 00000000..eecb278e --- /dev/null +++ b/prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlyCollection.java @@ -0,0 +1,89 @@ +package p.studio.utilities.structures; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Spliterator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +public class ReadOnlyCollection implements Iterable { + protected final Collection collection; + + protected ReadOnlyCollection(final Collection collection) { + this.collection = collection; + } + + public static ReadOnlyCollection empty() { + return ReadOnlyCollection.wrap(List.of()); + } + + public static ReadOnlyCollection wrap(final Collection collection) { + return new ReadOnlyCollection<>(collection); + } + + public static boolean isEmpty(final ReadOnlyCollection c) { + if (c == null) return true; + return c.isEmpty(); + } + + public static boolean isNotEmpty(final ReadOnlyCollection c) { + return !isEmpty(c); + } + + public int size() { + return collection.size(); + } + + public boolean isEmpty() { + return collection.isEmpty(); + } + + public boolean contains(final T o) { + return collection.contains(o); + } + + public boolean containsAll(final ReadOnlyCollection c) { + return c.stream().allMatch(collection::contains); + } + + public boolean containsAny(final ReadOnlyCollection c) { + return c.stream().anyMatch(collection::contains); + } + + public Iterator iterator() { + return collection.iterator(); + } + + public Stream stream() { + return collection.stream(); + } + + public Stream map(final Function mapper) { + return stream().map(mapper); + } + + public T[] toArray(final Supplier factory) { + return collection.toArray(factory.get()); + } + + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (o == null) return false; + if (o instanceof ReadOnlyCollection c) { + return c.collection.equals(collection); + } + return false; + } + + @Override + public int hashCode() { + return collection.hashCode(); + } + + public Spliterator spliterator() { + return collection.spliterator(); + } +} diff --git a/prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlyList.java b/prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlyList.java new file mode 100644 index 00000000..bb69b58d --- /dev/null +++ b/prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlyList.java @@ -0,0 +1,86 @@ +package p.studio.utilities.structures; + +import java.util.*; +import java.util.stream.Stream; + +public class ReadOnlyList extends ReadOnlyCollection { + private ReadOnlyList(final List list) { + super(list); + } + + public static ReadOnlyList empty() { + return ReadOnlyList.wrap(List.of()); + } + + public static ReadOnlyList wrap(final List list) { + return new ReadOnlyList<>(list); + } + + public static ReadOnlyList wrap(final ReadOnlyCollection c) { + if (ReadOnlyCollection.isEmpty(c)) return ReadOnlyList.empty(); + return ReadOnlyList.wrap(new ArrayList<>(c.collection)); + } + + public static ReadOnlyCollection wrap(final Set set) { + return new ReadOnlyCollection<>(List.copyOf(set)); + } + + @SafeVarargs + public static ReadOnlyList from(final T... values) { + if (values == null) return ReadOnlyList.empty(); + if (values.length == 0) return ReadOnlyList.empty(); + return ReadOnlyList.wrap(Stream.of(values).toList()); + } + + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (o == null) return false; + if (o instanceof ReadOnlyList c) { + return c.collection.equals(collection); + } + return false; + } + + public T get(final int index) { + return ((List)collection).get(index); + } + + public int indexOf(final T o) { + return ((List)collection).indexOf(o); + } + + public int lastIndexOf(final T o) { + return ((List)collection).lastIndexOf(o); + } + + public ListIterator listIterator() { + return ((List)collection).listIterator(); + } + + public ListIterator listIterator(final int index) { + return ((List)collection).listIterator(index); + } + + public ReadOnlyList subList(final int fromIndex, final int toIndex) { + return ReadOnlyList.wrap(((List)collection).subList(fromIndex, toIndex)); + } + + public T getFirst() { + return ((List)collection).getFirst(); + } + + public T getLast() { + return ((List)collection).getLast(); + } + + public ReadOnlyList sort(final Comparator c) { + Stream s = collection.stream(); + if (Objects.isNull(c)) { + s = s.sorted(); + } else { + s = s.sorted(c); + } + return ReadOnlyList.wrap(s.toList()); + } +} diff --git a/prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlySet.java b/prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlySet.java new file mode 100644 index 00000000..a4e2ccb5 --- /dev/null +++ b/prometeu-infra/src/main/java/p/studio/utilities/structures/ReadOnlySet.java @@ -0,0 +1,36 @@ +package p.studio.utilities.structures; + +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ReadOnlySet extends ReadOnlyCollection { + protected ReadOnlySet(final Set set) { + super(set); + } + + public static ReadOnlySet empty() { + return ReadOnlySet.wrap(Set.of()); + } + + public static ReadOnlySet wrap(final Set set) { + return new ReadOnlySet<>(set); + } + + @SafeVarargs + public static ReadOnlySet from(final T... values) { + if (values == null) return ReadOnlySet.empty(); + if (values.length == 0) return ReadOnlySet.empty(); + return ReadOnlySet.wrap(Stream.of(values).collect(Collectors.toSet())); + } + + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (o == null) return false; + if (o instanceof ReadOnlySet c) { + return c.collection.equals(collection); + } + return false; + } +} diff --git a/prometeu-studio/src/test/java/p/studio/app/MessageUtilsTest.java b/prometeu-studio/src/test/java/p/studio/app/MessageUtilsTest.java deleted file mode 100644 index 607c04de..00000000 --- a/prometeu-studio/src/test/java/p/studio/app/MessageUtilsTest.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This source file was generated by the Gradle 'init' task - */ -package p.studio.app; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class MessageUtilsTest { - @Test void testGetMessage() { - assertEquals("Hello World!", MessageUtils.getMessage()); - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index fa0bc71b..5419e75e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,6 +4,13 @@ plugins { rootProject.name = "prometeu-studio" -include(":prometeu-infra") -include("prometeu-compiler") +include("prometeu-infra") + +include("prometeu-compiler:frontends:prometeu-frontend-pbs") +include("prometeu-compiler:prometeu-compiler-core") +include("prometeu-compiler:prometeu-build-pipeline") +include("prometeu-compiler:prometeu-deps") +include("prometeu-compiler:prometeu-frontend-api") +include("prometeu-compiler:prometeu-frontend-registry") + include("prometeu-studio") \ No newline at end of file