use std::collections::BTreeSet;
use rucc_ir::term::heads;
const MODEL: &str = include_str!("../rules/ir.model");
fn defined() -> BTreeSet<&'static str> {
MODEL
.lines()
.filter_map(|line| line.strip_prefix("(semantics ("))
.map(|rest| rest.split([' ', ')', '\n']).next().unwrap_or(rest))
.collect()
}
fn named() -> BTreeSet<&'static str> {
heads().into_iter().map(|(_, name)| name).collect()
}
#[test]
fn every_entry_starts_a_line_of_its_own() {
let written = MODEL.matches("(semantics ").count();
assert_eq!(defined().len(), written, "an entry is not where the scan looks for it");
}
#[test]
fn a_head_with_no_meaning_here_is_one_whose_meaning_belongs_to_the_target() {
let missing: Vec<&str> = named().difference(&defined()).copied().collect();
assert_eq!(
missing,
[
"load.f32",
"load.f64",
"load.i16",
"load.i32",
"load.i64",
"load.i8",
"store.f32",
"store.f64",
"store.i16",
"store.i32",
"store.i64",
"store.i8",
]
);
}
#[test]
fn nothing_here_gives_a_meaning_to_a_head_no_instruction_has() {
let named = named();
let extra: Vec<&str> = defined()
.into_iter()
.filter(|head| !named.contains(head) && !head.starts_with("value."))
.collect();
assert!(extra.is_empty(), "the model names something the IR does not: {extra:?}");
}
#[test]
fn one_bit_has_its_meanings_here() {
let defined = defined();
for head in ["value.i1", "iconst.i1", "and.i1", "or.i1", "xor.i1", "brif.i1", "zext.i1.i32"] {
assert!(defined.contains(head), "{head} has no meaning in the IR model");
}
}