use sim_codec::{DecodeBudget, DecodeLimits};
use sim_kernel::{CodecId, Expr, SourceId, Symbol};
use sim_lib_lang_cl::cl_lite_source_cases;
use sim_lib_lang_scheme::r7rs_small_expr_cases;
use crate::GeneratedCoverageReport;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LandmarkCorpus {
pub language: Symbol,
pub citation: Symbol,
pub curated_fidelity_level: u8,
pub landmarks: Vec<Expr>,
}
impl LandmarkCorpus {
pub fn new(
language: Symbol,
citation: Symbol,
curated_fidelity_level: u8,
landmarks: Vec<Expr>,
) -> Self {
Self {
language,
citation,
curated_fidelity_level: curated_fidelity_level.min(5),
landmarks,
}
}
pub fn reconcile(&self, report: &GeneratedCoverageReport) -> CoverageVerdict {
if report.language != self.language {
return self.unanchored("report language does not match landmark corpus");
}
if let Some(missing) = self.missing_from_seed(report).first() {
return self.unanchored(format!("curated landmark absent from run: {missing:?}"));
}
if let Some(unmet) = self.unmet_in_report(report).first() {
return self.unanchored(format!(
"curated landmark not reproduced by generator: {unmet:?}"
));
}
let Some(coverage_percent) = report.coverage_percent() else {
return self.unanchored("generated coverage has no publishable percentage");
};
let measured_level = coverage_level(coverage_percent);
CoverageVerdict::Anchored {
citation: self.citation.clone(),
coverage_percent,
curated_fidelity_level: self.curated_fidelity_level,
claim_level: measured_level.min(self.curated_fidelity_level),
}
}
fn missing_from_seed(&self, report: &GeneratedCoverageReport) -> Vec<Expr> {
self.landmarks
.iter()
.filter(|landmark| !report.seed.iter().any(|seed| seed.canonical_eq(landmark)))
.cloned()
.collect()
}
fn unmet_in_report(&self, report: &GeneratedCoverageReport) -> Vec<Expr> {
self.landmarks
.iter()
.filter(|landmark| {
report
.unmet_landmarks
.iter()
.any(|unmet| unmet.canonical_eq(landmark))
})
.cloned()
.collect()
}
fn unanchored(&self, reason: impl Into<String>) -> CoverageVerdict {
CoverageVerdict::Unanchored {
citation: self.citation.clone(),
reason: reason.into(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum CoverageVerdict {
Anchored {
citation: Symbol,
coverage_percent: f32,
curated_fidelity_level: u8,
claim_level: u8,
},
Unanchored {
citation: Symbol,
reason: String,
},
}
pub fn r7rs_small_landmark_corpus() -> LandmarkCorpus {
LandmarkCorpus::new(
Symbol::new("scheme"),
Symbol::new("r7rs-small"),
1,
r7rs_small_expr_cases()
.into_iter()
.filter_map(|case| {
case.expected_display
.as_deref()
.and_then(expr_from_expected_display)
})
.collect(),
)
}
pub fn common_lisp_lite_landmark_corpus() -> LandmarkCorpus {
LandmarkCorpus::new(
Symbol::new("common-lisp"),
Symbol::new("cl-hyperspec"),
1,
cl_lite_source_cases()
.into_iter()
.filter_map(|case| parse_cl_landmark(&case.source))
.collect(),
)
}
fn parse_cl_landmark(source: &str) -> Option<Expr> {
let mut budget = DecodeBudget::new(DecodeLimits::default());
sim_lib_lang_cl::parse_cl_lite_source(
CodecId(0),
SourceId("cl-lite-landmark".to_owned()),
source,
&mut budget,
)
.ok()
.map(|tree| tree.expr)
}
fn expr_from_expected_display(display: &str) -> Option<Expr> {
match display {
"Expr::Bool(true)" => Some(Expr::Bool(true)),
"Expr::Bool(false)" => Some(Expr::Bool(false)),
_ => None,
}
}
fn coverage_level(coverage_percent: f32) -> u8 {
if !coverage_percent.is_finite() || coverage_percent <= 0.0 {
return 0;
}
(coverage_percent / 20.0).floor().min(5.0) as u8
}
#[cfg(test)]
mod tests {
use sim_kernel::NumberLiteral;
use super::*;
fn report(
language: Symbol,
seed: Vec<Expr>,
unmet_landmarks: Vec<Expr>,
) -> GeneratedCoverageReport {
GeneratedCoverageReport {
language,
sampled: 4,
round_tripped: 4,
mismatched: 0,
diagnostics: 0,
max_depth: 2,
seed,
landmark_reproduced: unmet_landmarks.is_empty(),
unmet_landmarks,
}
}
#[test]
fn anchored_report_publishes_clamped_coverage() {
let landmark = Expr::Bool(true);
let corpus = LandmarkCorpus::new(
Symbol::new("scheme"),
Symbol::new("r7rs-small"),
2,
vec![landmark.clone()],
);
let report = report(Symbol::new("scheme"), vec![landmark], Vec::new());
let verdict = corpus.reconcile(&report);
assert_eq!(
verdict,
CoverageVerdict::Anchored {
citation: Symbol::new("r7rs-small"),
coverage_percent: 100.0,
curated_fidelity_level: 2,
claim_level: 2,
}
);
}
#[test]
fn missing_landmark_is_unanchored() {
let corpus = LandmarkCorpus::new(
Symbol::new("scheme"),
Symbol::new("r7rs-small"),
1,
vec![Expr::Bool(true)],
);
let report = report(Symbol::new("scheme"), vec![Expr::Bool(false)], Vec::new());
let verdict = corpus.reconcile(&report);
assert!(matches!(
verdict,
CoverageVerdict::Unanchored { citation, reason }
if citation == Symbol::new("r7rs-small")
&& reason.contains("absent from run")
));
}
#[test]
fn unmet_landmark_is_unanchored() {
let landmark = Expr::Bool(true);
let corpus = LandmarkCorpus::new(
Symbol::new("scheme"),
Symbol::new("r7rs-small"),
1,
vec![landmark.clone()],
);
let report = report(
Symbol::new("scheme"),
vec![landmark.clone()],
vec![landmark],
);
let verdict = corpus.reconcile(&report);
assert!(matches!(
verdict,
CoverageVerdict::Unanchored { reason, .. }
if reason.contains("not reproduced")
));
}
#[test]
fn scheme_corpus_uses_curated_expr_landmarks() {
let corpus = r7rs_small_landmark_corpus();
assert_eq!(corpus.language, Symbol::new("scheme"));
assert_eq!(corpus.citation, Symbol::new("r7rs-small"));
assert_eq!(corpus.landmarks, vec![Expr::Bool(true)]);
}
#[test]
fn common_lisp_corpus_uses_curated_row_sources() {
let corpus = common_lisp_lite_landmark_corpus();
assert_eq!(corpus.language, Symbol::new("common-lisp"));
assert_eq!(corpus.citation, Symbol::new("cl-hyperspec"));
assert!(
corpus
.landmarks
.contains(&Expr::Symbol(Symbol::new("profile")))
);
assert!(
corpus
.landmarks
.iter()
.any(|expr| { matches!(expr, Expr::List(items) if items.len() == 2) })
);
}
#[test]
fn zero_or_invalid_coverage_levels_do_not_raise_claims() {
assert_eq!(coverage_level(0.0), 0);
assert_eq!(coverage_level(f32::NAN), 0);
assert_eq!(coverage_level(19.9), 0);
assert_eq!(coverage_level(20.0), 1);
assert_eq!(coverage_level(100.0), 5);
assert_eq!(coverage_level(250.0), 5);
let numeric = Expr::Number(NumberLiteral {
domain: Symbol::qualified("numbers", "i64"),
canonical: "1".to_owned(),
});
let corpus = LandmarkCorpus::new(
Symbol::new("scheme"),
Symbol::new("r7rs-small"),
5,
vec![numeric.clone()],
);
let mut report = report(Symbol::new("scheme"), vec![numeric], Vec::new());
report.round_tripped = 0;
assert_eq!(
corpus.reconcile(&report),
CoverageVerdict::Anchored {
citation: Symbol::new("r7rs-small"),
coverage_percent: 0.0,
curated_fidelity_level: 5,
claim_level: 0,
}
);
}
}