Refactor: Optimize block handling in optimizer
The optimizer now correctly handles empty blocks by collapsing them into Nop nodes. It also unwraps blocks containing a single expression, making the AST more concise. This change improves AST simplification by ensuring that redundant block structures are removed.
This commit is contained in:
@@ -562,10 +562,6 @@ impl Optimizer {
|
||||
new_exprs.push(opt);
|
||||
}
|
||||
|
||||
if !block_changed {
|
||||
return node_rc;
|
||||
}
|
||||
|
||||
if self.enabled {
|
||||
if new_exprs.is_empty() {
|
||||
return Rc::new(folder.make_nop_node(node));
|
||||
@@ -574,6 +570,10 @@ impl Optimizer {
|
||||
}
|
||||
}
|
||||
|
||||
if !block_changed {
|
||||
return node_rc;
|
||||
}
|
||||
|
||||
(NodeKind::Block { exprs: new_exprs }, node.ty.clone())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,50 @@
|
||||
use myc::ast::environment::Environment;
|
||||
|
||||
// ── Block simplification ─────────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn test_empty_block_eliminated() {
|
||||
// (do) is semantically Void/Nop — the optimizer must collapse it,
|
||||
// even though nothing inside the block changes (block_changed stays false).
|
||||
let env = Environment::new();
|
||||
let dump = env.dump_ast("(do)").unwrap();
|
||||
assert!(
|
||||
!dump.contains("Block"),
|
||||
"Empty block must be collapsed to Nop. Dump:\n{}",
|
||||
dump
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_expr_block_unwrapped() {
|
||||
// (do 42) carries exactly one expression — the Block wrapper is redundant.
|
||||
// The optimizer must unwrap it to a bare Constant node.
|
||||
let env = Environment::new();
|
||||
let result = env.run_script("(do 42)").unwrap();
|
||||
assert_eq!(format!("{}", result), "42");
|
||||
let dump = env.dump_ast("(do 42)").unwrap();
|
||||
assert!(
|
||||
!dump.contains("Block"),
|
||||
"Single-expression block must be unwrapped. Dump:\n{}",
|
||||
dump
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inner_empty_block_eliminated() {
|
||||
// The inner (do) must be collapsed to Nop during recursive optimization.
|
||||
// Nop-pruning in the outer block then removes it, leaving just Constant(42).
|
||||
let env = Environment::new();
|
||||
let result = env.run_script("(do (do) 42)").unwrap();
|
||||
assert_eq!(format!("{}", result), "42");
|
||||
let dump = env.dump_ast("(do (do) 42)").unwrap();
|
||||
assert!(
|
||||
!dump.contains("Block"),
|
||||
"Inner empty block must be eliminated entirely. Dump:\n{}",
|
||||
dump
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_optimizer_destructuring_inlining_and_mutation() {
|
||||
let env = Environment::new();
|
||||
|
||||
Reference in New Issue
Block a user