use super::super::super::HighLevelEmitter;
use super::braces::find_matching_brace;
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);
}
}
#[test]
fn find_matching_brace_closes_at_combined_else_line() {
let statements = stmts(&["if cond {", " a;", "} else {", " b;", "}"]);
assert_eq!(find_matching_brace(&statements, 0), Some(2));
let separate = stmts(&["if cond {", " a;", "}", "else {", " b;", "}"]);
assert_eq!(find_matching_brace(&separate, 0), Some(2));
}