use super::super::HighLevelEmitter;
const OVERFLOW_BOUNDS: &[&str] = &[
"-2147483648", "0", "-9223372036854775808", "2147483647", "4294967295", "9223372036854775807", "18446744073709551615", ];
impl HighLevelEmitter {
pub(crate) fn collapse_overflow_checks(statements: &mut [String]) {
let mut index = 0;
while index < statements.len() {
if let Some(collapse) = try_match_overflow(statements, index) {
apply_collapse(statements, &collapse);
continue;
}
index += 1;
}
}
}
struct OverflowCollapse {
op_line: usize,
expr: String,
result_var: String,
blank_start: usize,
blank_end: usize,
is_checked: bool,
else_unwrap: Option<(usize, usize)>,
}
fn next_code_line(statements: &[String], start: usize) -> Option<usize> {
statements
.iter()
.enumerate()
.skip(start)
.find(|(_, stmt)| {
let trimmed = stmt.trim();
!trimmed.is_empty() && !trimmed.starts_with("//")
})
.map(|(i, _)| i)
}
fn try_match_overflow(statements: &[String], idx: usize) -> Option<OverflowCollapse> {
let line0 = statements[idx].trim();
if line0.is_empty() || line0.starts_with("//") {
return None;
}
let (result_var, expr) = parse_let_assignment(line0)?;
let dup_idx = next_code_line(statements, idx + 1)?;
let line1 = statements[dup_idx].trim();
let (dup_var, dup_rhs) = parse_let_assignment(line1)?;
if dup_rhs != result_var {
return None;
}
let bound_idx = next_code_line(statements, dup_idx + 1)?;
let line2 = statements[bound_idx].trim();
let (_bound_var, bound_val) = parse_let_assignment(line2)?;
if !OVERFLOW_BOUNDS.contains(&bound_val.as_str()) {
return None;
}
let if_idx = next_code_line(statements, bound_idx + 1)?;
let line3 = statements[if_idx].trim();
if !line3.starts_with("if ") || !line3.ends_with('{') {
return None;
}
if !line3.contains(&format!("{dup_var} <"))
&& !line3.contains(&format!("{dup_var} =="))
&& !line3.contains(&format!("{dup_var} >"))
{
return None;
}
let if_block_end = find_matching_brace(statements, if_idx)?;
let first_body = ((if_idx + 1)..statements.len())
.find(|&i| {
let t = statements[i].trim();
!t.is_empty() && !t.starts_with("//")
})
.map(|i| statements[i].trim().to_string());
let is_checked = first_body
.as_deref()
.is_some_and(|s| s.starts_with("throw("));
let (blank_end, else_unwrap) = if is_checked {
let unwrap = next_code_line(statements, if_block_end + 1).and_then(|next| {
let trimmed = statements[next].trim();
if trimmed == "else {" || trimmed == "} else {" {
let else_end = find_matching_brace(statements, next)?;
Some((next, else_end))
} else {
None
}
});
(if_block_end, unwrap)
} else {
let block_end = find_overflow_block_end(statements, if_idx)?;
(block_end, None)
};
Some(OverflowCollapse {
op_line: idx,
expr: expr.to_string(),
result_var: result_var.to_string(),
blank_start: idx + 1,
blank_end,
is_checked,
else_unwrap,
})
}
fn apply_collapse(statements: &mut [String], collapse: &OverflowCollapse) {
let indent = leading_whitespace(&statements[collapse.op_line]);
if collapse.is_checked {
let wrapped = if collapse.expr.starts_with("checked(") {
collapse.expr.clone()
} else {
format!("checked({})", collapse.expr)
};
statements[collapse.op_line] = format!("{indent}let {} = {wrapped};", collapse.result_var);
}
for statement in statements
.iter_mut()
.take(collapse.blank_end + 1)
.skip(collapse.blank_start)
{
statement.clear();
}
if let Some((else_open, else_close)) = collapse.else_unwrap {
statements[else_open].clear();
statements[else_close].clear();
}
if !collapse.is_checked {
fixup_downstream_reference(statements, collapse.blank_end + 1, &collapse.result_var);
}
}
fn fixup_downstream_reference(statements: &mut [String], start: usize, result_var: &str) {
let Some(idx) = next_code_line(statements, start) else {
return;
};
let line = statements[idx].trim();
if line.starts_with("let ") || line.starts_with("if ") || line.starts_with("//") {
return;
}
if let Some((lhs, rhs)) = parse_bare_assignment(line) {
if rhs != result_var && is_temp_identifier(&rhs) {
let indent = leading_whitespace(&statements[idx]);
statements[idx] = format!("{indent}{lhs} = {result_var};");
}
}
}
fn parse_bare_assignment(line: &str) -> Option<(String, String)> {
let semi_pos = line.find(';')?;
let body = &line[..semi_pos];
let eq_pos = body.find(" = ")?;
let lhs = body[..eq_pos].trim();
if lhs.starts_with("let ") {
return None;
}
let rhs = body[eq_pos + 3..].trim();
Some((lhs.to_string(), rhs.to_string()))
}
fn is_temp_identifier(s: &str) -> bool {
s.starts_with('t') && s.len() > 1 && s[1..].chars().all(|c| c.is_ascii_digit())
}
fn leading_whitespace(s: &str) -> &str {
let trimmed = s.trim_start();
&s[..s.len() - trimmed.len()]
}
fn parse_let_assignment(line: &str) -> Option<(String, String)> {
let rest = line.strip_prefix("let ")?;
let semi_pos = rest.find(';')?;
let rest = &rest[..semi_pos];
let eq_pos = rest.find(" = ")?;
let var = rest[..eq_pos].trim().to_string();
let rhs = rest[eq_pos + 3..].trim().to_string();
Some((var, rhs))
}
fn find_overflow_block_end(statements: &[String], if_idx: usize) -> Option<usize> {
let mut end = find_matching_brace(statements, if_idx)?;
if let Some(next) = next_code_line(statements, end + 1) {
let trimmed = statements[next].trim();
if trimmed == "else {" || trimmed == "} else {" {
if let Some(else_end) = find_matching_brace(statements, next) {
end = else_end;
}
}
}
Some(end)
}
fn find_matching_brace(statements: &[String], open_idx: usize) -> Option<usize> {
let mut depth = 1i32;
for (i, stmt) in statements.iter().enumerate().skip(open_idx + 1) {
let trimmed = stmt.trim();
if trimmed.is_empty() || trimmed.starts_with("//") {
continue;
}
if trimmed.ends_with('{') {
depth += 1;
}
if trimmed == "}" || trimmed.starts_with("} ") {
depth -= 1;
if depth == 0 {
return Some(i);
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
fn stmts(lines: &[&str]) -> Vec<String> {
lines.iter().map(|s| s.to_string()).collect()
}
#[test]
fn collapses_unchecked_int32_add() {
let mut s = stmts(&[
"let t0 = a + b;",
"let t1 = t0;",
"let t2 = -2147483648;",
"if t1 < t2 {",
"goto label_0x001A;",
"let t3 = t0;",
"let t4 = 2147483647;",
"if t3 > t4 {",
"let t5 = 4294967295;",
"let t6 = t0 & t5;",
"}",
"}",
]);
HighLevelEmitter::collapse_overflow_checks(&mut s);
assert_eq!(s[0], "let t0 = a + b;");
for (i, line) in s.iter().enumerate().take(12).skip(1) {
assert!(line.is_empty(), "line {i} should be blank: {:?}", line);
}
}
#[test]
fn collapses_checked_int32_add() {
let mut s = stmts(&[
"let t0 = a + b;",
"let t1 = t0;",
"let t2 = -2147483648;",
"if t1 < t2 {",
"throw(t0);",
"let t3 = 2147483647;",
"throw(t3);",
"return;",
"}",
]);
HighLevelEmitter::collapse_overflow_checks(&mut s);
assert_eq!(s[0], "let t0 = checked(a + b);");
for (i, line) in s.iter().enumerate().take(9).skip(1) {
assert!(line.is_empty(), "line {i} should be blank: {:?}", line);
}
}
#[test]
fn collapses_unsigned_range_check() {
let mut s = stmts(&[
"let t0 = a + b;",
"let t1 = t0;",
"let t2 = 0;",
"if t1 < t2 {",
"goto label_0x0084;",
"let t3 = t0;",
"let t4 = 4294967295;",
"if t3 > t4 {",
"let t5 = 4294967295;",
"let t6 = t0 & t5;",
"return t6;",
"}",
"}",
]);
HighLevelEmitter::collapse_overflow_checks(&mut s);
assert_eq!(s[0], "let t0 = a + b;");
for (i, line) in s.iter().enumerate().take(13).skip(1) {
assert!(line.is_empty(), "line {i} should be blank: {:?}", line);
}
}
#[test]
fn collapses_int64_range_check() {
let mut s = stmts(&[
"let t0 = a + b;",
"let t1 = t0;",
"let t2 = -9223372036854775808;",
"if t1 < t2 {",
"goto label_0x01AC;",
"}",
]);
HighLevelEmitter::collapse_overflow_checks(&mut s);
assert_eq!(s[0], "let t0 = a + b;");
for (i, line) in s.iter().enumerate().take(6).skip(1) {
assert!(line.is_empty(), "line {i} should be blank: {:?}", line);
}
}
#[test]
fn does_not_match_unrelated_if() {
let mut s = stmts(&[
"let t0 = a + b;",
"let t1 = t0;",
"let t2 = 42;",
"if t1 < t2 {",
"return t0;",
"}",
]);
let original = s.clone();
HighLevelEmitter::collapse_overflow_checks(&mut s);
assert_eq!(s, original);
}
#[test]
fn handles_negate_equality_check() {
let mut s = stmts(&[
"let t0 = a;",
"let t1 = t0;",
"let t2 = -2147483648;",
"if t1 == t2 {",
"throw(a);",
"return;",
"}",
]);
HighLevelEmitter::collapse_overflow_checks(&mut s);
assert_eq!(s[0], "let t0 = checked(a);");
for (i, line) in s.iter().enumerate().take(7).skip(1) {
assert!(line.is_empty(), "line {i} should be blank: {:?}", line);
}
}
#[test]
fn skips_interleaved_comments() {
let mut s = stmts(&[
"let t5 = t4 + 1;",
"// 0029: DUP",
"let t6 = t5; // duplicate top of stack",
"// 002A: PUSHINT32",
"let t7 = -2147483648;",
"// 002F: JMPGE",
"if t6 < t7 {",
"}",
"else {",
"// 0033: DUP",
"let t8 = t5; // duplicate top of stack",
"// 0034: PUSHINT32",
"let t9 = 2147483647;",
"// 0039: JMPLE",
"if t8 > t9 {",
"}",
"// 003B: PUSHINT64",
"let t10 = 4294967295;",
"// 0044: AND",
"let t11 = t5 & t10;",
"// 0045: DUP",
"let t12 = t11; // duplicate top of stack",
"// 0046: PUSHINT32",
"let t13 = 2147483647;",
"// 004B: JMPLE",
"if t12 > t13 {",
"// 004D: PUSHINT64",
"let t14 = 4294967296;",
"// 0056: SUB",
"let t15 = t11 - t14;",
"}",
"let t5 = t15;",
"}",
]);
HighLevelEmitter::collapse_overflow_checks(&mut s);
assert_eq!(s[0], "let t5 = t4 + 1;");
for (i, line) in s.iter().enumerate().skip(1) {
assert!(line.is_empty(), "line {i} should be blank: {:?}", line);
}
}
#[test]
fn handles_if_else_without_comments() {
let mut s = stmts(&[
"let t0 = a + b;",
"let t1 = t0;",
"let t2 = -2147483648;",
"if t1 < t2 {",
"}",
"else {",
"let t3 = t0;",
"let t4 = 2147483647;",
"if t3 > t4 {",
"}",
"let t5 = 4294967295;",
"let t6 = t0 & t5;",
"}",
]);
HighLevelEmitter::collapse_overflow_checks(&mut s);
assert_eq!(s[0], "let t0 = a + b;");
for (i, line) in s.iter().enumerate().skip(1) {
assert!(line.is_empty(), "line {i} should be blank: {:?}", line);
}
}
#[test]
fn preserves_indentation() {
let mut s = stmts(&[
" let t0 = a + b;",
" let t1 = t0;",
" let t2 = -2147483648;",
" if t1 < t2 {",
" throw(t0);",
" }",
]);
HighLevelEmitter::collapse_overflow_checks(&mut s);
assert_eq!(s[0], " let t0 = checked(a + b);");
for (i, line) in s.iter().enumerate().take(6).skip(1) {
assert!(line.is_empty(), "line {i} should be blank: {:?}", line);
}
}
}