Skip to content

Phase 23: Package System — Multi-File FTL mit Imports - #44

Merged
MarcoFPO merged 1 commit into
mainfrom
feature/phase-23-package-system
Mar 14, 2026
Merged

Phase 23: Package System — Multi-File FTL mit Imports#44
MarcoFPO merged 1 commit into
mainfrom
feature/phase-23-package-system

Conversation

@MarcoFPO

Copy link
Copy Markdown
Owner

Summary

  • Import-Syntax: import "path/to/module.ftl" in PEG-Grammatik
  • AST: Program.imports: Vec<String> Feld
  • Import-Resolution: Zirkuläre/fehlende/doppelte Imports erkannt
  • CLI: check/build lösen Imports automatisch auf
  • MCP: flux_check mit optionalem base_path Parameter
  • 6 Testdateien + 6 Package-Tests

Test plan

  • 371 Tests bestehen (6 neue Package-Tests)
  • Bestehende Single-File Programme unverändert funktional
  • Clippy fehlerfrei
  • CI grün

Closes #36

🤖 Generated with Claude Code

Add import statement support to FTL, enabling multi-file programs:

- Grammar: `import "path/to/module.ftl"` before node definitions
- AST: `Program.imports: Vec<String>` (empty for existing programs)
- Parser: parses import_stmt rules, strips quotes from paths
- Pipeline: `resolve_imports()` recursively resolves imports with:
  - Circular import detection
  - Duplicate node ID detection across modules
  - Relative path resolution from importing file
- Pipeline: `run_check_program()` / `run_check_program_with_bmc()`
  accept pre-parsed Programs (for use after import resolution)
- CLI: cmd_check and cmd_build resolve imports for file-based input
- MCP: flux_check accepts optional `base_path` for import resolution
- Tests: 6 new tests covering success, circular, missing, duplicate,
  no-imports, and parse-syntax cases

Backward compatible: programs without imports work exactly as before.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Dieser Pull Request führt ein Paket-System für FTL ein, das die Entwicklung von Multi-Datei-Programmen durch einen Import-Mechanismus ermöglicht. Dies verbessert die Modularität und Wiederverwendbarkeit von FTL-Code erheblich, indem es Entwicklern erlaubt, ihre Programme in separate Module zu organisieren und diese über import-Anweisungen zu kombinieren. Das System kümmert sich um die Auflösung von Importen, einschließlich der Erkennung und Meldung von häufigen Problemen wie zirkulären Abhängigkeiten oder fehlenden Dateien, und integriert sich nahtlos in die bestehenden check- und build-Befehle.

Highlights

  • Import-Syntax: Eine neue import "path/to/module.ftl"-Syntax wurde zur PEG-Grammatik hinzugefügt, um das Einbinden anderer FTL-Dateien zu ermöglichen.
  • AST-Erweiterung: Die Program-Struktur im Abstract Syntax Tree (AST) wurde um ein imports: Vec<String>-Feld erweitert, um die deklarierten Importe zu speichern.
  • Import-Auflösung: Eine robuste Logik zur Auflösung von Importen wurde implementiert, die zirkuläre Importe, fehlende Dateien und doppelte Node-IDs über Module hinweg erkennt und entsprechende Fehler meldet.
  • CLI- und MCP-Integration: Die flux_check- und flux_build-Befehle in der Kommandozeile sowie das flux_mcp-Tool unterstützen nun die automatische Import-Auflösung, wenn ein base_path angegeben wird.
  • Neue Tests: Sechs neue Testdateien und sechs Paket-Integrationstests wurden hinzugefügt, um die Funktionalität des Importsystems zu validieren, einschließlich Erfolgsfällen und Fehlerbehandlung.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • flux-ftl/src/ast.rs
    • Feld imports: Vec<String> zur Program-Struktur hinzugefügt.
  • flux-ftl/src/bin/flux-mcp.rs
    • Beschreibung des flux_check-Tools aktualisiert, um die Unterstützung von Multi-Datei-Programmen über Importe zu erwähnen.
    • Parameter base_path zum input_schema von flux_check hinzugefügt.
    • Logik zur Auflösung von Importen in handle_flux_check implementiert, wenn base_path bereitgestellt wird.
  • flux-ftl/src/evolution.rs
    • Das imports-Feld in der Program-Struktur bei der Initialisierung als leer festgelegt.
  • flux-ftl/src/grammar.pest
    • Die program-Regel geändert, um import_stmt vor statement zu erlauben.
    • Die import_stmt-Regel für import "string_lit" hinzugefügt.
  • flux-ftl/src/main.rs
    • Funktion parse_and_resolve hinzugefügt, um das Parsen und die Import-Auflösung für CLI-Befehle zu handhaben.
    • Die Funktionen cmd_check und cmd_build geändert, um parse_and_resolve für dateibasierte Eingaben zu verwenden.
  • flux-ftl/src/optimizer.rs
    • Das imports-Feld beim Erstellen neuer Program-Instanzen in Optimierungsfunktionen geklont.
  • flux-ftl/src/parser.rs
    • Die Funktion parse_program geändert, um import_stmts in den imports-Vektor zu sammeln.
    • Die Instanziierung der Program-Struktur aktualisiert, um die gesammelten imports einzuschließen.
  • flux-ftl/src/pipeline.rs
    • Imports für HashSet und Path hinzugefügt.
    • Funktionen run_check_program und run_check_program_with_bmc eingeführt, um bereits geparste Program-ASTs zu verarbeiten.
    • Funktionen resolve_imports und resolve_imports_recursive für die Import-Auflösung implementiert, einschließlich der Behandlung von zirkulären Importen, fehlenden Dateien und doppelten Node-IDs.
    • Hilfsfunktion check_duplicate_ids hinzugefügt.
  • flux-ftl/src/prover.rs
    • Das imports-Feld in der Program-Struktur in Test-Helfern als leer initialisiert.
  • flux-ftl/src/region_checker.rs
    • Das imports-Feld in der Program-Struktur in Test-Helfern als leer initialisiert.
  • flux-ftl/src/type_checker.rs
    • Das imports-Feld in der Program-Struktur in Test-Helfern als leer initialisiert.
  • flux-ftl/src/validator.rs
    • Das imports-Feld in der Program-Struktur in Test-Helfern als leer initialisiert.
  • flux-ftl/testdata/module_a.ftl
    • Neue Testdatei hinzugefügt, die gemeinsame Typen und Konstanten definiert.
  • flux-ftl/testdata/module_circular_a.ftl
    • Neue Testdatei für zirkuläre Importtests (A importiert B) hinzugefügt.
  • flux-ftl/testdata/module_circular_b.ftl
    • Neue Testdatei für zirkuläre Importtests (B importiert A) hinzugefügt.
  • flux-ftl/testdata/module_duplicate.ftl
    • Neue Testdatei für doppelte Node-ID-Tests hinzugefügt.
  • flux-ftl/testdata/module_main.ftl
    • Neue Testdatei hinzugefügt, die ein Hauptmodul demonstriert, das module_a importiert.
  • flux-ftl/testdata/module_missing_import.ftl
    • Neue Testdatei für fehlende Importtests hinzugefügt.
  • flux-ftl/tests/evolution_tests.rs
    • Das imports-Feld in der Program-Struktur in Test-Helfern als leer initialisiert.
  • flux-ftl/tests/optimizer_tests.rs
    • Das imports-Feld in der Program-Struktur in Test-Helfern als leer initialisiert.
  • flux-ftl/tests/package_tests.rs
    • Neue Testdatei mit Integrationstests für das Paket-System hinzugefügt, die erfolgreiche Auflösung, zirkuläre Importe, fehlende Dateien, doppelte IDs und das Parsen der Import-Syntax abdecken.
  • flux-ftl/tests/prover_tests.rs
    • Das imports-Feld in der Program-Struktur in Test-Helfern als leer initialisiert.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@MarcoFPO
MarcoFPO merged commit 4f98540 into main Mar 14, 2026
1 check passed
@MarcoFPO
MarcoFPO deleted the feature/phase-23-package-system branch March 14, 2026 20:19

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a multi-file program import mechanism for FTL. It adds an imports field to the Program AST, updates the grammar to recognize import statements, and implements recursive import resolution in the pipeline module, including checks for circular imports, missing files, and duplicate node IDs. The flux-mcp and flux CLI tools are updated to support a base_path for import resolution, and various test helpers are adjusted to initialize the new imports field. Review comments suggest refactoring the import handling logic in flux-mcp.rs to improve readability and reduce complexity, and refactoring the check_duplicate_ids function in pipeline.rs to use iterators for better maintainability and conciseness.

Comment on lines +311 to +338
let result = if let Some(bp) = base_path {
let parse_result = flux_ftl::parser::parse_ftl(ftl_source);
match parse_result.status {
flux_ftl::error::Status::Ok => {
if let Some(ast) = parse_result.ast {
if !ast.imports.is_empty() {
let path = std::path::Path::new(bp);
match pipeline::resolve_imports(&ast, path) {
Ok(merged) => pipeline::run_check_program_with_bmc(merged, bmc_config),
Err(errs) => {
send_tool_error(stdout, id, &format!("Import resolution failed: {}", errs.join("; ")));
return;
}
}
} else {
pipeline::run_check_program_with_bmc(ast, bmc_config)
}
} else {
pipeline::run_check_with_bmc(ftl_source, bmc_config)
}
}
flux_ftl::error::Status::Error => {
pipeline::run_check_with_bmc(ftl_source, bmc_config)
}
}
} else {
pipeline::run_check_with_bmc(ftl_source, bmc_config)
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Die Logik zur Behandlung von Importen ist recht verschachtelt und enthält mehrfache Aufrufe von pipeline::run_check_with_bmc. Dies kann die Lesbarkeit und Wartbarkeit erschweren.

Ich schlage eine Refaktorisierung vor, um die Logik zu vereinfachen. Zuerst wird versucht, das Programm durch Parsen und Auflösen von Importen zu erhalten. Wenn dies fehlschlägt oder nicht anwendbar ist, wird auf die Überprüfung des rohen Quellcodes zurückgegriffen. Dies reduziert die Komplexität und Codeduplizierung.

    let result = if let Some(bp) = base_path {
        let parse_result = flux_ftl::parser::parse_ftl(ftl_source);
        if let Some(ast) = parse_result.ast {
            if ast.imports.is_empty() {
                pipeline::run_check_program_with_bmc(ast, bmc_config)
            } else {
                let path = std::path::Path::new(bp);
                match pipeline::resolve_imports(&ast, path) {
                    Ok(merged) => pipeline::run_check_program_with_bmc(merged, bmc_config),
                    Err(errs) => {
                        send_tool_error(stdout, id, &format!("Import resolution failed: {}", errs.join("; ")));
                        return;
                    }
                }
            }
        } else {
            // Parsing failed, run check on raw source to get errors
            pipeline::run_check_with_bmc(ftl_source, bmc_config)
        }
    } else {
        // No base_path, run check on raw source
        pipeline::run_check_with_bmc(ftl_source, bmc_config)
    };

Comment thread flux-ftl/src/pipeline.rs
Comment on lines +320 to +355
fn check_duplicate_ids(
main: &Program,
imported: &Program,
import_path: &str,
errors: &mut Vec<String>,
) {
let mut existing: HashSet<String> = HashSet::new();
for t in &main.types { existing.insert(t.id.0.clone()); }
for r in &main.regions { existing.insert(r.id.0.clone()); }
for c in &main.computes { existing.insert(c.id.0.clone()); }
for e in &main.effects { existing.insert(e.id.0.clone()); }
for k in &main.controls { existing.insert(k.id.0.clone()); }
for v in &main.contracts { existing.insert(v.id.0.clone()); }
for m in &main.memories { existing.insert(m.id.0.clone()); }
for x in &main.externs { existing.insert(x.id.0.clone()); }

let check = |id: &str| {
if existing.contains(id) {
Some(format!(
"duplicate node ID '{}' from import '{}'",
id, import_path
))
} else {
None
}
};

for t in &imported.types { if let Some(e) = check(&t.id.0) { errors.push(e); } }
for r in &imported.regions { if let Some(e) = check(&r.id.0) { errors.push(e); } }
for c in &imported.computes { if let Some(e) = check(&c.id.0) { errors.push(e); } }
for e_def in &imported.effects { if let Some(e) = check(&e_def.id.0) { errors.push(e); } }
for k in &imported.controls { if let Some(e) = check(&k.id.0) { errors.push(e); } }
for v in &imported.contracts { if let Some(e) = check(&v.id.0) { errors.push(e); } }
for m in &imported.memories { if let Some(e) = check(&m.id.0) { errors.push(e); } }
for x in &imported.externs { if let Some(e) = check(&x.id.0) { errors.push(e); } }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Die Funktion check_duplicate_ids ist sehr repetitiv. Sowohl das Sammeln der existierenden IDs als auch das Prüfen der importierten IDs wird für jeden Knotentyp einzeln durchgeführt. Das macht den Code schwer lesbar und fehleranfällig bei zukünftigen Erweiterungen.

Sie könnten dies refaktorisieren, indem Sie Iteratoren verketten, um alle IDs auf einmal zu sammeln und zu prüfen. Das würde den Code erheblich verkürzen und die Wartbarkeit verbessern.

fn check_duplicate_ids(
    main: &Program,
    imported: &Program,
    import_path: &str,
    errors: &mut Vec<String>,
) {
    let existing_ids: HashSet<_> = main.types.iter().map(|n| &n.id.0)
        .chain(main.regions.iter().map(|n| &n.id.0))
        .chain(main.computes.iter().map(|n| &n.id.0))
        .chain(main.effects.iter().map(|n| &n.id.0))
        .chain(main.controls.iter().map(|n| &n.id.0))
        .chain(main.contracts.iter().map(|n| &n.id.0))
        .chain(main.memories.iter().map(|n| &n.id.0))
        .chain(main.externs.iter().map(|n| &n.id.0))
        .collect();

    let imported_ids = imported.types.iter().map(|n| &n.id.0)
        .chain(imported.regions.iter().map(|n| &n.id.0))
        .chain(imported.computes.iter().map(|n| &n.id.0))
        .chain(imported.effects.iter().map(|n| &n.id.0))
        .chain(imported.controls.iter().map(|n| &n.id.0))
        .chain(imported.contracts.iter().map(|n| &n.id.0))
        .chain(imported.memories.iter().map(|n| &n.id.0))
        .chain(imported.externs.iter().map(|n| &n.id.0));

    for id in imported_ids {
        if existing_ids.contains(id) {
            errors.push(format!(
                "duplicate node ID '{}' from import '{}'",
                id, import_path
            ));
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 23: Package System — Multi-File FTL mit Imports

1 participant