Merge pull request #628 from MarekSpodBiedry:issue-527

This commit is contained in:
Brandon Thomas 2026-10-12 23:21:52 -04:00
commit 3794892f28
2 changed files with 36 additions and 4 deletions

View File

@ -224,10 +224,20 @@ fn write_expr(s: &mut String, e: &Expr, r1c1: Option<CellRef>) {
}
},
},
Expr::Binary(op, a, b) => {
write_expr(s, a, r1c1);
s.push_str(op.symbol());
write_expr(s, b, r1c1);
Expr::Binary(..) => {
// Walk the left spine iteratively: a flat chain such as `1+1+1+...` parses into a
// tree one level deeper per operator, and recursing on it could exhaust the stack.
let mut rest: Vec<(&BinOp, &Expr)> = Vec::new();
let mut first = e;
while let Expr::Binary(op, a, b) = first {
rest.push((op, b));
first = a;
}
write_expr(s, first, r1c1);
for (op, right) in rest.into_iter().rev() {
s.push_str(op.symbol());
write_expr(s, right, r1c1);
}
}
Expr::Call(name, args) => {
s.push_str(name);

View File

@ -301,3 +301,25 @@ fn trim_references_adjust() {
let refs: Vec<String> = parse("SUM(Sheet2!A1:.B5)").unwrap().references().iter().map(|r| printer::reference_a1(r)).collect();
assert_eq!(refs, ["Sheet2!A1:B5"]);
}
#[test]
fn prints_long_flat_chain_without_deep_recursion() {
// Small stack: a recursive printer overflows long before 20000 levels.
let handle = std::thread::Builder::new()
.stack_size(256 * 1024)
.spawn(|| {
let mut e = Expr::Number(1.0);
for _ in 0..20000 {
e = Expr::Binary(BinOp::Add, Box::new(e), Box::new(Expr::Number(1.0)));
}
let text = print(&e);
let r1c1 = print_r1c1(&e, gridcraft_core::CellRef { row: 0, col: 0 });
// Dropping the deep tree recurses; leak it so only the printer is under test.
std::mem::forget(e);
(text, r1c1)
})
.expect("spawn");
let (text, r1c1) = handle.join().expect("printer must not overflow the stack");
assert_eq!(text, vec!["1"; 20001].join("+"));
assert_eq!(r1c1, text);
}