Skip to main content

sim_lib_lang_genconf/
registry.rs

1//! Registry for generated language-conformance rows.
2
3use sim_kernel::{Cx, Symbol};
4
5use crate::{ExprSpace, GeneratedCoverageReport, run_generated_row};
6
7/// One generated conformance row: language id, codec id, and expression space.
8pub struct GenerativeRow {
9    /// Language row measured by this generated conformance entry.
10    pub language: Symbol,
11    /// Codec for encoding and decoding generated expressions for this row.
12    pub codec: Symbol,
13    /// Expression space sampled for this row.
14    pub space: ExprSpace,
15}
16
17/// Returns every language codec measured by generated conformance.
18///
19/// Adding a language is adding one row here with the language row id, reader
20/// codec id, and shared expression space.
21pub fn generative_registry() -> Vec<GenerativeRow> {
22    vec![
23        row("scheme", "scheme-r7rs-small"),
24        row("common-lisp", "common-lisp-lite"),
25        row("clojure", "clojure-edn"),
26        row("islisp", "islisp"),
27        row("julia", "algol"),
28        row("lua", "algol"),
29        row("ruby", "algol"),
30        row("typed-lazy", "algol"),
31        core_round_trip_row("prolog", "lisp"),
32    ]
33}
34
35/// Runs generated conformance for every registered language row.
36pub fn run_all_generated(cx: &mut Cx, budget: usize) -> Vec<GeneratedCoverageReport> {
37    generative_registry()
38        .into_iter()
39        .map(|row| run_generated_row(cx, &row.language, &row.codec, &row.space, budget))
40        .collect()
41}
42
43fn row(language: &str, codec: &str) -> GenerativeRow {
44    GenerativeRow {
45        language: Symbol::new(language),
46        codec: Symbol::qualified("codec", codec),
47        space: ExprSpace::r7rs_core_space(3),
48    }
49}
50
51fn core_round_trip_row(language: &str, codec: &str) -> GenerativeRow {
52    GenerativeRow {
53        language: Symbol::new(language),
54        codec: Symbol::qualified("codec", codec),
55        space: ExprSpace::core_round_trip_space(3),
56    }
57}
58
59#[cfg(test)]
60mod closure_tests {
61    use std::collections::BTreeSet;
62    use std::sync::Arc;
63
64    use sim_kernel::{Cx, DefaultFactory, EagerPolicy, Symbol};
65    use sim_lib_lang_matrix::language_matrix;
66
67    use super::*;
68
69    fn closure_cx() -> Cx {
70        let mut cx = Cx::new(Arc::new(EagerPolicy), Arc::new(DefaultFactory));
71        sim_test_support::register_core_classes(&mut cx);
72        sim_test_support::register_f64_number_domain(&mut cx);
73        cx
74    }
75
76    #[test]
77    fn closure_registry_tracks_the_curated_language_matrix() {
78        let registry = generative_registry();
79        let matrix = language_matrix();
80        let mut names = BTreeSet::new();
81
82        assert_eq!(registry.len(), matrix.language_count());
83        assert_eq!(matrix.language_count(), 9);
84        for row in &registry {
85            assert!(
86                names.insert(row.language.clone()),
87                "duplicate generated row: {}",
88                row.language,
89            );
90            assert!(
91                matrix.row(&row.language).is_some(),
92                "{} row must stay in the curated matrix",
93                row.language,
94            );
95        }
96    }
97
98    #[test]
99    fn closure_registry_uses_live_language_codec_ids() {
100        let registry = generative_registry();
101
102        assert!(registry.iter().any(|row| {
103            row.language == Symbol::new("scheme")
104                && row.codec == Symbol::qualified("codec", "scheme-r7rs-small")
105        }));
106        assert!(registry.iter().any(|row| {
107            row.language == Symbol::new("common-lisp")
108                && row.codec == Symbol::qualified("codec", "common-lisp-lite")
109        }));
110        assert!(registry.iter().any(|row| {
111            row.language == Symbol::new("prolog") && row.codec == Symbol::qualified("codec", "lisp")
112        }));
113    }
114
115    #[test]
116    fn closure_reports_are_anchored_or_honest() {
117        let mut cx = closure_cx();
118        let reports = run_all_generated(&mut cx, 8);
119
120        assert_eq!(reports.len(), generative_registry().len());
121        for report in &reports {
122            if !report.landmark_reproduced() {
123                assert!(
124                    report.coverage_percent().is_none(),
125                    "{} must not publish unanchored coverage",
126                    report.language,
127                );
128            }
129        }
130        assert_eq!(language_matrix().language_count(), 9);
131    }
132}