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);
|
new_exprs.push(opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !block_changed {
|
|
||||||
return node_rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.enabled {
|
if self.enabled {
|
||||||
if new_exprs.is_empty() {
|
if new_exprs.is_empty() {
|
||||||
return Rc::new(folder.make_nop_node(node));
|
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())
|
(NodeKind::Block { exprs: new_exprs }, node.ty.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,50 @@
|
|||||||
use myc::ast::environment::Environment;
|
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]
|
#[test]
|
||||||
fn test_optimizer_destructuring_inlining_and_mutation() {
|
fn test_optimizer_destructuring_inlining_and_mutation() {
|
||||||
let env = Environment::new();
|
let env = Environment::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user