vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! Law-breaking mutations.

/// Falsely claim a law by prefixing its name.
#[inline]
pub fn apply_falsely_claim(source: &str, law: &str, op: &str) -> String {
    replace_in_op_scope(source, op, law, &format!("FalselyClaimed({})", law))
}

/// Corrupt the claimed identity element.
#[inline]
pub fn apply_identity_corrupt(source: &str, op: &str, wrong: u32) -> String {
    replace_in_op_scope(source, op, "identity: 0", &format!("identity: {}", wrong))
}

/// Corrupt the claimed absorbing element.
#[inline]
pub fn apply_absorbing_corrupt(source: &str, op: &str, wrong: u32) -> String {
    replace_in_op_scope(source, op, "absorbing: 0", &format!("absorbing: {}", wrong))
}

fn replace_in_op_scope(source: &str, op: &str, pattern: &str, replacement: &str) -> String {
    let Some(scope) = op_scope(source, op) else {
        return source.to_string();
    };
    let inner = &source[scope.clone()];
    let replaced = crate::adversarial::mutations::catalog::lexical::replace_code(
        inner,
        pattern,
        replacement,
        1,
    );
    if replaced == inner {
        return source.to_string();
    }
    format!(
        "{}{}{}",
        &source[..scope.start],
        replaced,
        &source[scope.end..]
    )
}

fn op_scope(source: &str, op: &str) -> Option<std::ops::Range<usize>> {
    let id_patterns = [
        format!("id: \"{op}\""),
        format!("op: \"{op}\""),
        format!("op_id: \"{op}\""),
    ];
    for pattern in id_patterns {
        if let Some(id_pos) =
            crate::adversarial::mutations::catalog::lexical::find_code(source, &pattern)
        {
            let open = source[..id_pos].rfind('{').unwrap_or(0);
            let close = matching_close_brace(source, open)?;
            return Some(open..close);
        }
    }
    None
}

fn matching_close_brace(source: &str, open: usize) -> Option<usize> {
    let mut depth = 0usize;
    let mut i = open;
    while i < source.len() {
        if !crate::adversarial::mutations::catalog::lexical::is_code_index(source, i) {
            i += source[i..].chars().next()?.len_utf8();
            continue;
        }
        let ch = source[i..].chars().next()?;
        if ch == '{' {
            depth += 1;
        } else if ch == '}' {
            depth = depth.checked_sub(1)?;
            if depth == 0 {
                return Some(i + ch.len_utf8());
            }
        }
        i += ch.len_utf8();
    }
    None
}