# Analyse von `src/ast/environment.rs` ## 1. Struktur von `Environment` Die `Environment`-Struktur fungiert im Projekt als zentraler "State-Manager" und Orchestrator. Sie hält den globalen Zustand für den gesamten Lebenszyklus eines Skripts, von der Quelle bis zur Ausführung: * **Zustandsverwaltung (State Container):** Beinhaltet den globalen Programmzustand in Form von Registern und Caches. Nahezu alles ist in `Rc>` gekapselt (z.B. `root_types`, `root_values`, `root_scopes`, Caches für Optimierung und Monomorphisierung). * **Modulladung & Abhängigkeiten:** `preload_dependencies` und `discover_globals` lesen `#use`-Abhängigkeiten, durchsuchen den Code vorab nach globalen Definitionen (`def`) und Makros und laden die Standardbibliothek (`prelude.myc`). * **Kompilierungs-Pipeline:** Die Methoden `compile`, `compile_syntax`, `compile_pipeline` und `link` steuern den Code durch alle Compiler-Phasen: Macro-Expansion -> Binding -> Type-Checking -> Analysis -> Specialization -> Optimization -> Lowering. * **Makro-Evaluierung:** Die interne Struktur `RuntimeMacroEvaluator` wird genutzt, um AST-Knoten zur Compile-Zeit an eine VM zu übergeben und den Code für Makros auszuführen. * **Laufzeit-Ausführung & RTL (Runtime Library):** Methoden wie `run_script`, `run_debug` und `instantiate` starten die `VM`. Zudem gibt es Methoden (`register_native`, `allocate_slot`), um native Rust-Funktionen (Intrinsics) im globalen Scope (`fixed_scope_idx = 0`) zu registrieren. * **Dokumentations-Registry:** Es speichert sowohl RTL-Dokumentation als auch aus dem Source-Code extrahierte Kommentare (`myc_docs`). ## 2. Prüfung auf Boilerplate Der Code weist an mehreren Stellen typischen Rust-Boilerplate für Single-Threaded-Interpreter auf: * **Das `Rc`-Muster:** Um denselben globalen Zustand zwischen Parser, Compiler, Pipeline und VM zu teilen, bestehen 13 der 17 Felder aus `Rc>`. Das zwingt überall im Code zu redundantem `.borrow()`, `.borrow_mut()` und `.clone()` (z. B. beim Klonen in `RuntimeMacroEvaluator` über `get_expander`). * **Fehler-Mapping:** Beim Modulladen wird oft repetitiv mit `.map_err(|e: String| format!("...", e))` Boilerplate geschrieben, anstatt einen zentralen `Error`-Typen mit `thiserror` oder `anyhow` zu verwenden. * **Manuelle AST-Traversierung:** In `discover_globals` und `collect_doc_comments` wird der AST per Hand (mittels `match` und Rekursion) durchlaufen, anstatt ein zentrales "Visitor-Pattern" wiederzuverwenden. ## 3. Prüfung auf "unscharfe Interfaces" (Fuzzy Interfaces) Der Code enthält einige starke Indikatoren für unscharfe Systemgrenzen ("Leaky Abstractions") und Vermischung von Zuständigkeiten (God Object Smell): * **God Object:** `Environment` weiß zu viel. Es parst Dateien, wertet Makros aus, instanziiert den Typ-Prüfer (`TypeChecker`), betreibt Caching für Optimierer, startet die `VM` und sammelt nebenbei Doc-Strings. Eine klarere Trennung zwischen `CompilerEnvironment` (statische Phasen) und `RuntimeEnvironment` (VM-Zustand/Values) fehlt hier. * ~~**Verwaschene Kompilierungsschritte:**~~ **✓ Behoben (Design korrekt, ein Detail bereinigt).** Die drei Methoden bilden eine saubere Adapter-Hierarchie: `compile_pipeline` (Kern, Diagnostics-Sink) ← `compile` (public API, merged Parse+Compile-Fehler in `CompilationResult`) / `compile_syntax` (privater Adapter für Modul-Loader, konvertiert zu `Result<_, String>`). Das unterschiedliche Error-Reporting ist situations-appropriat, nicht inkonsistent. **Behobener Design-Geruch:** `dump_ast` umging zuvor `compile()` und verschluckte Parse-Fehler still. Behoben: `dump_ast` delegiert jetzt an `compile(source).into_result()?`. * ~~**Die `specialize_node`-Closure:**~~ **✓ Kein Problem (Design korrekt verstanden).** Die `compiler`-Closure ist kein Zeichen unsauberer Kapselung — im Gegenteil. `Specializer` ist bewusst von TypeChecker, Optimizer und VM entkoppelt; der `CompileFunc`-Typ (`specializer.rs:15`) ist der explizite **Dependency-Injection-Punkt** (Strategy Pattern). Die innere Pipeline (TypeCheck → Analyze → sub-Specialize → Optimize → Lower → VM.run) **dupliziert nicht** die äußere — ihr Zweck ist fundamental verschieden: sie erzeugt einen gecachten `Value` (compile-and-evaluate), während die äußere Pipeline einen `ExecNode` für die Skriptausführung erzeugt. Die Closure captured 6 `Rc>`-Handles statt `&self`, weil Rust keine `self`-Referenz in eine `'static`-Closure erlaubt — das ist der korrekte Rust-Weg. **Design-Limitation (dokumentiert, kein Bug):** Der `sub_specializer` innerhalb der Closure hat `compiler: None`, was Endlos-Rekursion verhindert, aber bedeutet, dass nur eine Spezialisierungsebene pro Aufruf expandiert wird. * ~~**Type-Checker Hack:**~~ **✓ Kein Problem (Kommentar bereinigt).** Der ursprüngliche Kommentar war veraltet und irreführend. Das `BoundLike`-Trait vereinigt alle Phasen mit identischer Binding-Struktur (`BoundPhase`, `TypedPhase`, `AnalyzedPhase`). `TypeChecker::check_node_as_bound()` ist korrekte Generic-Programmierung — kein Hack. Die Phasen passen sauber ineinander. Der Kommentar wurde durch eine korrekte Erklärung des Monomorphisierungs-Designs ersetzt. * **Konzeptioneller Bruch bei `instantiate`:** Diese Methode nimmt einen fertig kompilierten Ast (`ExecNode`) und wickelt ihn in eine `NativeFunction` ein. Dadurch wird ein in Myc geschriebenes Skript in der Registry strukturell als "native Rust-Funktion" getarnt. Das ist pragmatisch, verwischt aber die semantische Grenze zwischen User-Code (Closures) und echten Runtime-Intrinsics.