28 lines
4.5 KiB
Markdown
28 lines
4.5 KiB
Markdown
# 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<RefCell<T>>` 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<RefCell>`-Muster:** Um denselben globalen Zustand zwischen Parser, Compiler, Pipeline und VM zu teilen, bestehen 13 der 17 Felder aus `Rc<RefCell<...>>`. 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:** Die Methoden `compile`, `compile_syntax` und `compile_pipeline` haben überlappende Aufgabenbereiche. Mal wird das Error-Reporting über eine `Diagnostics`-Instanz gemacht, mal wird diese verworfen und stumpf in einen `Result<TypedNode, String>` umgewandelt.
|
|
* **Die `specialize_node`-Closure:** In `specialize_node` wird eine gigantische Inline-Closure (`compiler = Rc::new(move |...| { ... })`) definiert. Diese *baut tief im Inneren eine komplette Mini-Compiler-Pipeline samt VM-Ausführung nach*, nur um Konstanten zu falten / Aufrufe zu spezialisieren. Das zeigt, dass die Compiler-Pipeline nach außen hin nicht sauber gekapselt ist.
|
|
* ~~**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<P: BoundLike>()` 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.
|