flowlog-build 0.2.2

Build-time FlowLog compiler for library mode.
Documentation
mod errors;

use flowlog_build::common::SourceMap;
use flowlog_build::parser::{DirectiveKind, ParseError, Program};

use errors::{fixture, render};

fn parse(name: &str, extended: bool) -> (Result<Program, ParseError>, SourceMap) {
    let mut sm = SourceMap::new();
    let res = Program::parse(&fixture("parser", name), extended, &mut sm);
    (res, sm)
}

#[test]
fn duplicate_decl() {
    assert_err!(
        parse("duplicate_decl.dl", true),
        ParseError::DuplicateDecl { .. },
        [
            "duplicate declaration",
            "redeclared here",
            "first declared here",
            "edge",
        ]
    );
}

#[test]
fn duplicate_attribute() {
    assert_err!(
        parse("duplicate_attribute.dl", true),
        ParseError::DuplicateAttribute { .. },
        ["duplicate attribute", "first declared here", "edge"]
    );
}

#[test]
fn duplicate_directive() {
    assert_err!(
        parse("duplicate_directive.dl", true),
        ParseError::DuplicateDirective {
            kind: DirectiveKind::Output,
            ..
        },
        ["duplicate .output", "first directive here"]
    );
}

#[test]
fn undeclared_in_directive() {
    assert_err!(
        parse("undeclared_in_directive.dl", true),
        ParseError::UndeclaredInDirective { .. },
        [".output", "undeclared", "missing_rel"]
    );
}

#[test]
fn undeclared_iterative() {
    assert_err!(
        parse("undeclared_iterative.dl", true),
        ParseError::UndeclaredInIterativeList { .. },
        ["iterative", "ghost_rel"]
    );
}

#[test]
fn undeclared_loop_condition() {
    assert_err!(
        parse("undeclared_loop_condition.dl", true),
        ParseError::UndeclaredLoopCondition { .. },
        ["loop condition", "ghost_flag"]
    );
}

#[test]
fn undeclared_in_rule() {
    assert_err!(
        parse("undeclared_in_rule.dl", true),
        ParseError::UndeclaredInRule { .. },
        ["rule references undeclared relation", "ghost_rel"]
    );
}

#[test]
fn undeclared_in_fact() {
    assert_err!(
        parse("undeclared_in_fact.dl", true),
        ParseError::UndeclaredInFact { .. },
        ["fact references undeclared relation", "ghost_rel"]
    );
}

#[test]
fn non_nullary_loop_condition() {
    assert_err!(
        parse("non_nullary_loop_condition.dl", true),
        ParseError::NonNullaryLoopCondition { .. },
        ["must be nullary", "done_flag"]
    );
}

#[test]
fn placeholder_in_udf() {
    assert_err!(
        parse("placeholder_in_udf.dl", true),
        ParseError::PlaceholderInUdf { .. },
        ["`_` placeholder", "my_udf"]
    );
}

#[test]
fn syntax_error() {
    assert_err!(
        parse("syntax_error.dl", true),
        ParseError::Syntax { .. },
        ["syntax error"]
    );
}

#[test]
fn loop_in_standard_mode() {
    let (res, sm) = parse("loop_in_standard_mode.dl", false);
    let err = res.unwrap_err();
    assert!(
        matches!(err, ParseError::LoopBlockInStandardMode { .. }),
        "got {err:?}"
    );
    let out = render(err, &sm);
    assert!(
        out.contains("extend-batch") || out.contains("Extended"),
        "got: {out}"
    );
}

#[test]
fn circular_include() {
    assert_err!(
        parse("circular_include_a.dl", true),
        ParseError::CircularInclude { .. },
        [
            "circular include",
            "circular_include_a.dl",
            "include chain:"
        ]
    );
}

#[test]
fn include_io() {
    assert_err!(
        parse("include_io.dl", true),
        ParseError::IncludeIo { .. },
        ["failed to read", "nonexistent_file.dl"]
    );
}