3d0ea094b0
The `dump_ast` method previously bypassed the `compile` method, which meant it would silently ignore parsing errors. This commit ensures that `dump_ast` now delegates to `compile` and correctly propagates any parsing errors. This aligns the behavior of `dump_ast` with other compilation steps and provides better feedback to the user. Fix: Dump AST ignores parse errors The `dump_ast` method now delegates to `compile(source).into_result()?` to properly handle and report parse errors, ensuring consistency with the compilation process.
5.5 KiB
5.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:✓ 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 inCompilationResult) /compile_syntax(privater Adapter für Modul-Loader, konvertiert zuResult<_, String>). Das unterschiedliche Error-Reporting ist situations-appropriat, nicht inkonsistent. Behobener Design-Geruch:dump_astumging zuvorcompile()und verschluckte Parse-Fehler still. Behoben:dump_astdelegiert jetzt ancompile(source).into_result()?.Die✓ Kein Problem (Design korrekt verstanden). Diespecialize_node-Closure:compiler-Closure ist kein Zeichen unsauberer Kapselung — im Gegenteil.Specializerist bewusst von TypeChecker, Optimizer und VM entkoppelt; derCompileFunc-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 gecachtenValue(compile-and-evaluate), während die äußere Pipeline einenExecNodefür die Skriptausführung erzeugt. Die Closure captured 6Rc<RefCell<T>>-Handles statt&self, weil Rust keineself-Referenz in eine'static-Closure erlaubt — das ist der korrekte Rust-Weg. Design-Limitation (dokumentiert, kein Bug): Dersub_specializerinnerhalb der Closure hatcompiler: 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. 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.