aufbau 0.1.2

Generalized prefix parsing for a class of context-dependent languages
Documentation
use super::*;

#[cfg(test)]
fn imp_grammar() -> Grammar {
    load_example_grammar("imp")
}

pub fn valid_expressions_cases() -> Vec<ParseTestCase> {
    let cases = vec![
        ParseTestCase::valid("assign int", "{ let x:Int=5; }"),
        ParseTestCase::valid("assign int negative", "{ let x:Int=0-5; }"),
        ParseTestCase::valid("assign arithmetic", "{ let x:Int=1+2; }"),
        ParseTestCase::valid("assign bool", "{ let flag:Bool=true; }"),
        ParseTestCase::valid("assign union bool", "{ let u:Int|Bool=true; }"),
        ParseTestCase::valid("operation", "{ let x:Int=5; let y:Int=3; let z:Int=x+y; }"),
        ParseTestCase::valid(
            "long decl chain",
            "{ let a:Int=1; let b:Int=2; let c:Int=3; let d:Int=4; let e:Int=5; let f:Int=6; let g:Int=7; let h:Int=8; }",
        ),
        ParseTestCase::valid("sequential var reuse", "{ let x:Int=5; let y:Int=x; }"),
        ParseTestCase::valid("sequential var expr", "{ let x:Int=5; let y:Int=x+1; }"),
        ParseTestCase::valid("parentheses", "{ let x:Int=5; let y:Int=(x+1); }"),
        ParseTestCase::valid(
            "if expression",
            "{ if (1==1) { let x:Int=1; } else { let x:Int=2; } }",
        ),
        ParseTestCase::valid("while expression", "{ while (1==1) { let x:Int=1; } }"),
    ];

    cases
}

pub fn invalid_expressions_cases() -> Vec<ParseTestCase> {
    vec![
        ParseTestCase::invalid("assign before decl", "{x=5;"),
        ParseTestCase::invalid("missing type for declaration", "{let x=5;"),
        ParseTestCase::invalid("missing value", "{let x:Int;"),
        ParseTestCase::invalid("wrong type token", "{let x:String=5;"),
        ParseTestCase::invalid("lowercase type", "{let x:int=5;"),
        ParseTestCase::invalid("invalid operator", "{let x:Int=5%2;"),
        ParseTestCase::invalid("operator first", "{let x:Int=+5;"),
        ParseTestCase::invalid("double operator", "{let x:Int=1++2;"),
        ParseTestCase::invalid("extra close paren", "{let x:Int=(1+2));"),
        ParseTestCase::invalid("missing close paren", "{let x:Int=(1+2;"),
        ParseTestCase::invalid("missing open brace", "let"),
        ParseTestCase::invalid("close brace first", "}"),
        ParseTestCase::invalid("random chars", "@#$;"),
        ParseTestCase::invalid("missing block close", "{ let x:Int=1; "),
        ParseTestCase::invalid(
            "if missing else block brace",
            "{ if (1==1) { let x:Int=1; } else let y:Int=2; }",
        ),
        ParseTestCase::invalid(
            "while missing condition close",
            "{ while (1==1 { let x:Int=1; } }",
        ),
        ParseTestCase::invalid("unbound var", "{ let y:Int=x; }"),
        ParseTestCase::invalid("unbound var", "{ let y:Int=1; let z:Int=y-x; }"),
        ParseTestCase::invalid("use before decl", "{ let y:Int=x+1; let x:Int=5; }"),
        ParseTestCase::invalid("union mismatch", "{ let u:Int|Bool=1+2; let z:Int=u+1; }"),
        ParseTestCase::invalid(
            "union used as int",
            "{ let u:Int|Bool=true; let z:Int=u+1; }",
        ),
        ParseTestCase::invalid(
            "if branch context isolation",
            "{ if (1==1) { let x:Int=1; } else { let y:Int=x; } }",
        ),
        ParseTestCase::invalid(
            "while body does not leak bindings",
            "{ while (1==1) { let x:Int=1; } let y:Int=x; }",
        ),
        ParseTestCase::invalid(
            "if condition missing comparator",
            "{ if 1 { let x:Int=1; } else { let x:Int=2; } }",
        ),
        ParseTestCase::invalid(
            "while condition type mismatch",
            "{ while (1==true) { let x:Int=1; } }",
        ),
        ParseTestCase::invalid("bool declaration from int", "{ let flag:Bool=1; }"),
        ParseTestCase::invalid("assignment from bool to int", "{ let x:Int=1; x=true; }"),
    ]
}

#[test]
fn valid_expressions_imp() {
    let mut grammar = imp_grammar();
    let cases = valid_expressions_cases();

    println!("\n=== IMP Valid Expressions ({} cases) ===", cases.len());
    let (res, _cases_json) = run_parse_batch(&mut grammar, &cases);
    assert_eq!(res.failed, 0, "{}", res.format_failures());
    println!(
        "All {} tests passed in {:?} (avg: {:?})",
        cases.len(),
        res.total_duration,
        res.avg_duration
    );
}

#[test]
fn invalid_expressions_imp() {
    let mut grammar = imp_grammar();
    let cases = invalid_expressions_cases();
    println!("\n=== IMP Invalid Expressions ({} cases) ===", cases.len());
    let (res, _cases_json) = run_parse_batch(&mut grammar, &cases);
    assert_eq!(res.failed, 0, "{}", res.format_failures());
    println!(
        "All {} tests passed in {:?} (avg: {:?})",
        cases.len(),
        res.total_duration,
        res.avg_duration
    );
}