pub mod applied;
pub mod arithmetic;
pub mod bitwise;
pub mod buffer;
pub(crate) mod catalog;
pub mod comparison;
pub mod control;
pub mod ir_specific;
pub mod law;
pub(crate) mod lexical;
mod mutation;
pub use crate::spec::mutation_class::MutationClass;
pub use catalog::MUTATION_CATALOG;
pub use mutation::{apply, class_of, Mutation};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinOpKind {
Add,
Sub,
Mul,
Div,
Shl,
Shr,
And,
Or,
Xor,
Lt,
Le,
Gt,
Ge,
Eq,
Ne,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Branch {
If,
Else,
}
#[derive(Debug, Clone, PartialEq)]
pub enum MutationError {
UnsupportedMutation,
ApplyError(String),
}
impl core::fmt::Display for MutationError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
MutationError::UnsupportedMutation => {
f.write_str("mutation not supported for this source")
}
MutationError::ApplyError(s) => write!(f, "apply error: {s}"),
}
}
}
impl std::error::Error for MutationError {}
#[inline]
pub(crate) fn replace_operator(source: &str, old_op: &str, new_op: &str, count: usize) -> String {
let mut result = String::with_capacity(source.len());
let mut replaced = 0;
let mut i = 0;
while i < source.len() {
if replaced < count
&& crate::adversarial::mutations::catalog::lexical::is_code_index(source, i)
&& source[i..].starts_with(old_op)
{
let left_ok =
crate::adversarial::mutations::catalog::lexical::previous_non_ws(source, i)
.map(|c| c.is_alphanumeric() || c == '_' || c == ')' || c == ']')
.unwrap_or(false);
let right_idx = i + old_op.len();
let right_ok =
crate::adversarial::mutations::catalog::lexical::next_non_ws(source, right_idx)
.map(|c| c.is_alphanumeric() || c == '_' || c == '(' || c == '[')
.unwrap_or(false);
if left_ok && right_ok {
result.push_str(new_op);
i += old_op.len();
replaced += 1;
continue;
}
}
if let Some(c) = source[i..].chars().next() {
result.push(c);
i += c.len_utf8();
} else {
break;
}
}
result
}