use rucc_ir::Func;
use crate::Fuel;
pub trait Pass: Sync {
fn name(&self) -> &'static str;
fn describe(&self) -> &'static str;
fn run(&self, func: &mut Func, fuel: &mut Fuel) -> bool;
}
pub static PASSES: &[&dyn Pass] =
&[&crate::fold::Fold, &crate::simplify::Simplify, &crate::dce::Dce];
#[must_use]
pub fn find(name: &str) -> Option<&'static dyn Pass> {
PASSES.iter().copied().find(|pass| pass.name() == name)
}
#[cfg(test)]
mod tests {
use super::PASSES;
#[test]
fn every_pass_has_a_name_a_flag_could_carry() {
for pass in PASSES {
let name = pass.name();
assert!(!name.is_empty(), "a pass with no name cannot be turned off");
assert!(
name.bytes().all(|b| b.is_ascii_lowercase() || b == b'-'),
"`{name}` is not spelled the way a -f flag is"
);
assert!(!pass.describe().is_empty(), "`{name}` says nothing about itself");
}
}
#[test]
fn no_two_passes_share_a_name() {
for (index, pass) in PASSES.iter().enumerate() {
for other in &PASSES[index + 1..] {
assert_ne!(pass.name(), other.name(), "two passes answer to one name");
}
}
}
#[test]
fn a_pass_is_found_by_its_name_and_nothing_else_is() {
for pass in PASSES {
assert_eq!(super::find(pass.name()).map(super::Pass::name), Some(pass.name()));
}
assert!(super::find("no-such-pass").is_none());
}
}