vyre-conform 0.1.0

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

/// Shift the first array-index expression by `by`.
#[inline]
pub fn apply_index_shift(source: &str, by: i32) -> String {
    let mut i = 0;
    while i < source.len() {
        if crate::adversarial::mutations::catalog::lexical::is_code_index(source, i)
            && source[i..].starts_with('[')
        {
            let left_ok = i
                .checked_sub(1)
                .and_then(|j| source.get(j..=j))
                .map(|s| {
                    let c = s.chars().next().unwrap();
                    c.is_alphanumeric() || c == '_' || c == ']'
                })
                .unwrap_or(false);
            if left_ok {
                let start = i + 1;
                let mut depth = 1;
                let mut j = start;
                while let Some(c) = source.get(j..).and_then(|s| s.chars().next()) {
                    if c == '[' {
                        depth += 1;
                    } else if c == ']' {
                        depth -= 1;
                        if depth == 0 {
                            let inner = &source[start..j];
                            let suffix = if by >= 0 {
                                format!("+{}", by)
                            } else {
                                format!("{}", by)
                            };
                            return format!(
                                "{}[({}) {}]{}",
                                &source[..i],
                                inner,
                                suffix,
                                &source[j + c.len_utf8()..]
                            );
                        }
                    }
                    j += c.len_utf8();
                }
            }
        }
        if let Some(c) = source[i..].chars().next() {
            i += c.len_utf8();
        } else {
            break;
        }
    }
    source.to_string()
}

/// Clamp the first array-index expression to `new_index`.
#[inline]
pub fn apply_index_clamp(source: &str, new_index: &str) -> String {
    let mut i = 0;
    while i < source.len() {
        if crate::adversarial::mutations::catalog::lexical::is_code_index(source, i)
            && source[i..].starts_with('[')
        {
            let left_ok = i
                .checked_sub(1)
                .and_then(|j| source.get(j..=j))
                .map(|s| {
                    let c = s.chars().next().unwrap();
                    c.is_alphanumeric() || c == '_' || c == ']'
                })
                .unwrap_or(false);
            if left_ok {
                let start = i + 1;
                let mut depth = 1;
                let mut j = start;
                while let Some(c) = source.get(j..).and_then(|s| s.chars().next()) {
                    if c == '[' {
                        depth += 1;
                    } else if c == ']' {
                        depth -= 1;
                        if depth == 0 {
                            return format!(
                                "{}[{}]{}",
                                &source[..i],
                                new_index,
                                &source[j + c.len_utf8()..]
                            );
                        }
                    }
                    j += c.len_utf8();
                }
            }
        }
        if let Some(c) = source[i..].chars().next() {
            i += c.len_utf8();
        } else {
            break;
        }
    }
    source.to_string()
}

/// Swap `.read(` ↔ `.write(` and `load(` ↔ `store(`.
#[inline]
pub fn apply_read_write_swap(source: &str) -> String {
    let tmp = crate::adversarial::mutations::catalog::lexical::replace_code(
        source,
        ".read(",
        ".VYRE_TMP_READ.",
        usize::MAX,
    );
    let tmp = crate::adversarial::mutations::catalog::lexical::replace_code(
        &tmp,
        ".write(",
        ".read(",
        usize::MAX,
    );
    let tmp = crate::adversarial::mutations::catalog::lexical::replace_code_word(
        &tmp,
        "load",
        "VYRE_TMP_LOAD",
        usize::MAX,
    );
    let tmp = crate::adversarial::mutations::catalog::lexical::replace_code_word(
        &tmp,
        "store",
        "load",
        usize::MAX,
    );
    let tmp = crate::adversarial::mutations::catalog::lexical::replace_code(
        &tmp,
        ".VYRE_TMP_READ.",
        ".write(",
        usize::MAX,
    );
    crate::adversarial::mutations::catalog::lexical::replace_code_word(
        &tmp,
        "VYRE_TMP_LOAD",
        "store",
        usize::MAX,
    )
}

/// Weaken atomic memory orderings.
#[inline]
pub fn apply_ordering_weaken(source: &str) -> String {
    let source = crate::adversarial::mutations::catalog::lexical::replace_code(
        source,
        "Ordering::Release",
        "Ordering::Relaxed",
        usize::MAX,
    );
    let source = crate::adversarial::mutations::catalog::lexical::replace_code(
        &source,
        "Ordering::Acquire",
        "Ordering::Relaxed",
        usize::MAX,
    );
    crate::adversarial::mutations::catalog::lexical::replace_code(
        &source,
        "Ordering::SeqCst",
        "Ordering::Acquire",
        usize::MAX,
    )
}

/// Weaken acquire-release orderings specifically.
#[inline]
pub fn apply_acqrel_ordering_weaken(source: &str) -> String {
    crate::adversarial::mutations::catalog::lexical::replace_code(
        source,
        "Ordering::AcqRel",
        "Ordering::Relaxed",
        usize::MAX,
    )
}

/// Shift the first buffer count expression by `by`.
#[inline]
pub fn apply_count_shift(source: &str, by: i32) -> String {
    let replacement = if by >= 0 {
        format!("len.saturating_add({by})")
    } else {
        format!("len.saturating_sub({})", by.unsigned_abs())
    };
    let shifted = crate::adversarial::mutations::catalog::lexical::replace_code_word(
        source,
        "count",
        &replacement,
        1,
    );
    if shifted != source {
        return shifted;
    }
    let replacement = if by >= 0 {
        format!(".len().saturating_add({by})")
    } else {
        format!(".len().saturating_sub({})", by.unsigned_abs())
    };
    crate::adversarial::mutations::catalog::lexical::replace_code(source, ".len()", &replacement, 1)
}