4.5 KiB
4.5 KiB
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_dependenciesunddiscover_globalslesen#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_pipelineundlinksteuern den Code durch alle Compiler-Phasen: Macro-Expansion -> Binding -> Type-Checking -> Analysis -> Specialization -> Optimization -> Lowering. - Makro-Evaluierung: Die interne Struktur
RuntimeMacroEvaluatorwird 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_debugundinstantiatestarten dieVM. 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 ausRc<RefCell<...>>. Das zwingt überall im Code zu redundantem.borrow(),.borrow_mut()und.clone()(z. B. beim Klonen inRuntimeMacroEvaluatorüberget_expander). - Fehler-Mapping: Beim Modulladen wird oft repetitiv mit
.map_err(|e: String| format!("...", e))Boilerplate geschrieben, anstatt einen zentralenError-Typen mitthiserroroderanyhowzu verwenden. - Manuelle AST-Traversierung: In
discover_globalsundcollect_doc_commentswird der AST per Hand (mittelsmatchund 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:
Environmentweiß zu viel. Es parst Dateien, wertet Makros aus, instanziiert den Typ-Prüfer (TypeChecker), betreibt Caching für Optimierer, startet dieVMund sammelt nebenbei Doc-Strings. Eine klarere Trennung zwischenCompilerEnvironment(statische Phasen) undRuntimeEnvironment(VM-Zustand/Values) fehlt hier. - Verwaschene Kompilierungsschritte: Die Methoden
compile,compile_syntaxundcompile_pipelinehaben überlappende Aufgabenbereiche. Mal wird das Error-Reporting über eineDiagnostics-Instanz gemacht, mal wird diese verworfen und stumpf in einenResult<TypedNode, String>umgewandelt. - Die
specialize_node-Closure: Inspecialize_nodewird 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. DasBoundLike-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 eineNativeFunctionein. 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.