Add AST dumper and improve upvalue analysis

The `UpvalueAnalyzer` now correctly identifies which lambdas capture
which variable declarations, rather than just marking declarations that
need boxing. This information is stored in a `capture_map`.

The `Binder` has been updated to use this new `capture_map` instead of a
`HashSet` of boxed declarations. The `DefLocal` node in `bound_nodes.rs`
now stores a `captured_by` field, which is a list of lambda identities
that capture the local variable.

A new `dumper` module has been added to provide a human-readable
representation of the bound AST, including information about captured
variables.

The `VM` has been updated to use the `captured_by` field to determine if
a local variable needs to be stored in a `Cell`, rather than relying on
a boolean `is_boxed` flag.

An example script `extreme_capture.myc` has been added to test deep
nesting and variable capture.

A new "Dump AST" button has been added to the UI, which uses the new
`Dumper` to display the bound AST.
This commit is contained in:
Michael Schimmel
2026-02-18 00:35:08 +01:00
parent 4d9adccab5
commit 25e3bc1d01
10 changed files with 269 additions and 49 deletions
+19 -1
View File
@@ -85,7 +85,21 @@ impl CompilerApp {
);
}
Err(e) => {
self.output_log = format!("Error: {}", e);
self.output_log = format!("Error during Compilation/Execution: {}", e);
}
}
}
fn dump_ast(&mut self) {
match self.env.dump_ast(&self.source_code) {
Ok(dump) => {
self.output_log = format!(
"--- BOUND AST DUMP ---\n\n{}",
dump
);
}
Err(e) => {
self.output_log = format!("Error during AST Binding: {}", e);
}
}
}
@@ -213,6 +227,10 @@ impl eframe::App for CompilerApp {
self.compile();
}
if ui.button("Dump AST").clicked() {
self.dump_ast();
}
if let Some(path) = &self.current_example_path {
let file_name = path.file_name().unwrap_or_default().to_string_lossy();
if ui.button(format!("Save {} (Ctrl+S)", file_name)).clicked() {