workshop-rs 0.1.16

Canonical multi-locale Overwatch Workshop semantic core: catalog, parser, WIR, validation, emitter.
Documentation
//! Matrix-surface emission closure scan (#87 AC-17).
//!
//! For every construct family on the matrix-listed supported
//! surface, the native emitter's spelling must self-round-trip:
//! parse(emit(x)) reparses and re-emits byte-identically. Each case
//! below is a real `wright compile --profile compat` artifact of a
//! minimal supported-surface program; the scan asserts the emitted
//! spelling is a byte-identical fixed point of the ws parser/
//! emitter. Oracle-canonical spellings pinned by repros are
//! asserted in the emitter tests (AC-15/16).

use workshop_rs::catalog::{Catalog, Locale};
use workshop_rs::emitter;
use workshop_rs::parser;

fn catalog() -> Catalog {
    Catalog::builtin().unwrap()
}

fn en() -> Locale {
    Locale::new("en-US")
}

/// Parse an emitted artifact, re-emit, and assert byte-identity.
fn assert_closure(label: &str, artifact: &str) {
    let program = parser::parse(artifact, &catalog(), &en())
        .unwrap_or_else(|error| panic!("{label} must reparse: {error}"));
    let reemitted = emitter::emit(&program, &catalog(), &en())
        .unwrap_or_else(|error| panic!("{label} must re-emit: {error}"));
    assert_eq!(
        artifact, reemitted,
        "{label} emitted spelling must be a byte-identical fixed point"
    );
}

const ASSIGN_AUG: &str = "variables {\n    global:\n        0: g\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Set Global Variable(g, 1);\n        Modify Global Variable(g, Add, 2);\n        Modify Global Variable(g, Subtract, 1);\n        Modify Global Variable(g, Multiply, 2);\n    }\n}\n\n";
const CALLS: &str = "variables {\n    global:\n        0: g\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Set Global Variable(g, Count Of(Array(1, 2)));\n        Set Global Variable(g, 3);\n        Set Global Variable(g, 2);\n        Wait(1, Ignore Condition);\n    }\n}\n\n";
const CONDITIONS: &str = "variables {\n    global:\n        0: x\n    player:\n        0: p\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Each Player;\n        All;\n        All;\n    }\n    conditions {\n        (Event Player).p > 1;\n        Global.x == 0;\n    }\n    actions {\n        Disable Inspector Recording;\n    }\n}\n\n";
const DECL_INDEX: &str = "variables {\n    global:\n        3: x\n    player:\n        1: y\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Disable Inspector Recording;\n    }\n}\n\n";
const DECL_NUMS: &str = "variables {\n    global:\n        0: j\n        1: h\n        2: k\n    player:\n        0: p\n}\n\nrule (\"Initialize global variables\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Set Global Variable(j, 5);\n        Set Global Variable(k, 0.0);\n    }\n}\n\nrule (\"Initialize player variables\") {\n    event {\n        Ongoing - Each Player;\n        All;\n        All;\n    }\n    actions {\n        Set Player Variable(Event Player, p, 7);\n    }\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Disable Inspector Recording;\n    }\n}\n\n";
const EXPR_ESCAPES: &str = "variables {\n    global:\n        0: g\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Set Global Variable(g, Custom String(\"a\\nb\tc\\\"d\"));\n    }\n}\n\n";
const EXPR_LITERALS: &str = "variables {\n    global:\n        0: g\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Set Global Variable(g, Array(1, 2, 3));\n        Set Global Variable(g, Array(Custom String(\"a\"), Custom String(\"b\")));\n        Set Global Variable(g, Vector(1.5, -2, 3));\n        Set Global Variable(g, True);\n        Set Global Variable(g, 0.5);\n    }\n}\n\n";
const EXPR_LONG: &str = "variables {\n    global:\n        0: g\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Set Global Variable(g, Custom String(\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB{0}\", Custom String(\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB{0}\", Custom String(\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"))));\n    }\n}\n\n";
const FORMAT_FOLD: &str = "variables {\n    global:\n        0: z\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Set Global Variable(z, Custom String(\"v: 3\"));\n    }\n}\n\n";
const FORMAT_PARTIAL: &str = "variables {\n    global:\n        0: x\n        1: z\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Set Global Variable(z, Custom String(\"3 {0}\", Global.x));\n    }\n}\n\n";
const FORMAT_VAR: &str = "variables {\n    global:\n        0: x\n        1: z\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Set Global Variable(z, Custom String(\"v: {0}\", Global.x));\n    }\n}\n\n";
const IF_ELSE: &str = "variables {\n    global:\n        0: x\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        If(Compare(Global.x, ==, 1));\n            Disable Inspector Recording;\n        Else If(Compare(Global.x, ==, 2));\n            Disable Inspector Recording;\n        Else;\n            Disable Inspector Recording;\n    }\n}\n\n";
const IF_FINAL: &str = "variables {\n    global:\n        0: x\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        If(Compare(Global.x, ==, 1));\n            Disable Inspector Recording;\n    }\n}\n\n";
const LOOPS: &str = "variables {\n    global:\n        0: i\n        1: g\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        For Global Variable(i, 0, 3, 1);\n            Set Global Variable(g, Global.i);\n        End;\n        While(Compare(Global.g, <, 3));\n            Modify Global Variable(g, Add, 1);\n            Wait(1, Ignore Condition);\n        End;\n    }\n}\n\n";
const MACRO: &str = "variables {\n    global:\n        0: g\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Set Global Variable(g, 6);\n    }\n}\n\n";
const PLAYERVAR_READ: &str = "variables {\n    global:\n        0: g\n    player:\n        0: p\n        1: q\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Each Player;\n        All;\n        All;\n    }\n    actions {\n        Set Global Variable(g, (Event Player).p);\n        If(Compare(Add((Event Player).p, (Event Player).q), >, 1));\n            Disable Inspector Recording;\n    }\n}\n\n";
const SUBROUTINE: &str = "subroutines {\n    0: foo\n    1: bar\n}\n\nrule (\"Subroutine bar\") {\n    event {\n        Subroutine;\n        bar;\n    }\n    actions {\n        Disable Inspector Recording;\n    }\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Global;\n    }\n    actions {\n        Call Subroutine(foo);\n    }\n}\n\n";

const PVMOD: &str = "variables {\n    player:\n        0: p\n}\n\nrule (\"r\") {\n    event {\n        Ongoing - Each Player;\n        All;\n        All;\n    }\n    actions {\n        Modify Player Variable(Event Player, p, Add, 2);\n        Modify Player Variable(Event Player, p, Subtract, 1);\n        Modify Player Variable(Event Player, p, Multiply, 3);\n        Modify Player Variable(Event Player, p, Divide, 2);\n        Modify Player Variable(Event Player, p, Modulo, 5);\n    }\n}\n\n";

#[test]
fn emitted_spellings_self_round_trip_across_the_matrix_surface() {
    assert_closure("assign_aug", ASSIGN_AUG);
    assert_closure("calls", CALLS);
    assert_closure("conditions", CONDITIONS);
    assert_closure("pvmod", PVMOD);
    assert_closure("decl_index", DECL_INDEX);
    assert_closure("decl_nums", DECL_NUMS);
    assert_closure("expr_escapes", EXPR_ESCAPES);
    assert_closure("expr_literals", EXPR_LITERALS);
    assert_closure("expr_long", EXPR_LONG);
    assert_closure("format_fold", FORMAT_FOLD);
    assert_closure("format_partial", FORMAT_PARTIAL);
    assert_closure("format_var", FORMAT_VAR);
    assert_closure("if_else", IF_ELSE);
    assert_closure("if_final", IF_FINAL);
    assert_closure("loops", LOOPS);
    assert_closure("macro", MACRO);
    assert_closure("playervar_read", PLAYERVAR_READ);
    assert_closure("subroutine", SUBROUTINE);
}