Refactor instantiate to return Closure

The `instantiate` method in `Environment` has been refactored to return
`Result<Rc<Closure>, String>` instead of `Rc<NativeFunction>`. This
change separates the creation of a `Closure` from its execution,
allowing the caller to manage the `VM` lifecycle and choose the
appropriate execution strategy (e.g., single run vs. repeated benchmark
iterations).

The `NativeFunction` type is now exclusively used for true Rust
intrinsics. The benchmark runner has also been updated to reuse a single
`VM` across iterations, improving performance by avoiding repeated VM
allocations.
This commit is contained in:
2026-03-27 22:04:20 +01:00
parent 3d0ea094b0
commit b6dcdbde8d
4 changed files with 42 additions and 49 deletions
+1 -1
View File
@@ -24,4 +24,4 @@ Der Code enthält einige starke Indikatoren für unscharfe Systemgrenzen ("Leaky
* ~~**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<RefCell<T>>`-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<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.
* ~~**Konzeptioneller Bruch bei `instantiate`:**~~ **✓ Behoben.** `instantiate` gibt jetzt `Result<Rc<Closure>, String>` zurück statt `Rc<NativeFunction>`. Die VM-Erzeugung und -Ausführung liegt beim Aufrufer (`run_script_compiled`, Benchmark-Runner), der die passende Strategie kennt (einmaliger Run vs. N Iterationen mit VM-Reuse). `NativeFunction` bleibt ausschließlich für echte Rust-Intrinsics (RTL). Bonus: der Benchmark-Runner erstellt jetzt eine VM für N Iterationen statt N VMs — `run_with_args` resettet `stack` und `frames` am Anfang jedes Aufrufs, VM-Reuse ist sicher.