neo-decompiler 0.10.1

Neo N3 NEF decompiler: parse, disassemble, lift bytecode to high-level pseudocode and C# skeletons, with a CLI, JSON reports, and optional WebAssembly bindings.
Documentation
use super::super::super::HighLevelEmitter;

fn brace_balance(statements: &[String]) -> i32 {
    let mut balance = 0i32;
    for line in statements {
        let trimmed = line.trim();
        balance += trimmed.matches('{').count() as i32;
        balance -= trimmed.matches('}').count() as i32;
    }
    balance
}

#[test]
fn invert_empty_if_else_keeps_braces_balanced() {
    let mut statements = vec![
        "if cond {".to_string(),
        "}".to_string(),
        "else {".to_string(),
        "loc0 = 5;".to_string(),
        "}".to_string(),
        "return loc0;".to_string(),
    ];
    HighLevelEmitter::invert_empty_if_else(&mut statements);
    assert_eq!(brace_balance(&statements), 0, "unbalanced: {statements:?}");
    let joined = statements.join("\n");
    assert!(
        joined.contains("if !(cond) {\nloc0 = 5;\n}"),
        "inverted if must retain the else body and its closer: {joined}"
    );
}

#[test]
fn eliminate_identity_temps_substitutes_forward() {
    let mut statements = vec![
        "let t1 = arg0;".to_string(),
        "let t0 = t1;".to_string(),
        "return t0;".to_string(),
    ];
    HighLevelEmitter::eliminate_identity_temps(&mut statements);
    assert_eq!(statements[0], "let t1 = arg0;");
    assert_eq!(statements[1], "", "identity definition must be cleared");
    assert_eq!(statements[2], "return t1;");
}

#[test]
fn eliminate_identity_temps_skips_lhs_used_before_definition() {
    let mut statements = vec![
        "bar(t0);".to_string(),
        "let t0 = t1;".to_string(),
        "return t0;".to_string(),
    ];
    let before = statements.clone();
    HighLevelEmitter::eliminate_identity_temps(&mut statements);
    assert_eq!(
        statements, before,
        "identity with a prior use of lhs must be preserved unchanged"
    );
}

#[test]
fn invert_empty_if_else_wraps_compound_condition() {
    let mut statements = vec![
        "if a == 1 && b == 2 {".to_string(),
        "}".to_string(),
        "else {".to_string(),
        "loc0 = 5;".to_string(),
        "}".to_string(),
    ];
    HighLevelEmitter::invert_empty_if_else(&mut statements);
    assert_eq!(brace_balance(&statements), 0, "unbalanced: {statements:?}");
    assert!(
        statements
            .iter()
            .any(|s| s.trim() == "if !(a == 1 && b == 2) {"),
        "compound condition must be wrapped, not operator-flipped: {statements:?}"
    );
}