Skip to main content

sim_lib_lang_matrix/
lib.rs

1#![forbid(unsafe_code)]
2#![deny(missing_docs)]
3//! Assembly point for the SIM language conformance matrix.
4
5use sim_lib_lang_cl::cl_lite_matrix_row;
6use sim_lib_lang_clojure::clojure_core_matrix_row;
7use sim_lib_lang_islisp::islisp_matrix_row;
8use sim_lib_lang_julia::julia_core_matrix_row;
9use sim_lib_lang_lua::lua_core_matrix_row;
10use sim_lib_lang_prolog::prolog_matrix_row;
11use sim_lib_lang_ruby::ruby_dsl_matrix_row;
12use sim_lib_lang_scheme::r7rs_small_matrix_row;
13use sim_lib_lang_typed_lazy::typed_lazy_matrix_row;
14use sim_lib_standard_core::ConformanceMatrix;
15
16/// Builds the complete runtime language conformance matrix.
17pub fn language_matrix() -> ConformanceMatrix {
18    let mut matrix = ConformanceMatrix::new();
19    matrix.register(r7rs_small_matrix_row());
20    matrix.register(cl_lite_matrix_row());
21    matrix.register(clojure_core_matrix_row());
22    matrix.register(islisp_matrix_row());
23    matrix.register(julia_core_matrix_row());
24    matrix.register(lua_core_matrix_row());
25    matrix.register(ruby_dsl_matrix_row());
26    matrix.register(typed_lazy_matrix_row());
27    matrix.register(prolog_matrix_row());
28    matrix
29}
30
31/// Cookbook recipes for this lib, embedded at build time.
32pub static RECIPES: sim_cookbook::EmbeddedDir =
33    include!(concat!(env!("OUT_DIR"), "/cookbook_recipes.rs"));
34
35#[cfg(test)]
36mod tests {
37    use std::collections::BTreeSet;
38
39    use sim_kernel::Symbol;
40
41    use super::*;
42
43    #[test]
44    fn language_matrix_has_exactly_nine_rows() {
45        let matrix = language_matrix();
46
47        assert_eq!(matrix.language_count(), 9);
48    }
49
50    #[test]
51    fn language_matrix_has_no_duplicate_row_names() {
52        let matrix = language_matrix();
53        let names: Vec<_> = matrix
54            .iter_rows()
55            .map(|row| row.language.to_string())
56            .collect();
57        let unique: BTreeSet<_> = names.iter().cloned().collect();
58
59        assert_eq!(unique.len(), names.len());
60    }
61
62    #[test]
63    fn language_matrix_rows_are_populated() {
64        let matrix = language_matrix();
65
66        for language in [
67            "scheme",
68            "common-lisp",
69            "clojure",
70            "islisp",
71            "julia",
72            "lua",
73            "ruby",
74            "typed-lazy",
75            "prolog",
76        ] {
77            let row = matrix
78                .row(&Symbol::new(language))
79                .unwrap_or_else(|| panic!("{language} row must be registered"));
80            assert!(!row.is_empty(), "{language} row must have cases");
81        }
82    }
83}
84
85#[cfg(test)]
86mod closure_tests {
87    use std::collections::BTreeSet;
88    use std::sync::Arc;
89
90    use sim_kernel::{Cx, DefaultFactory, EagerPolicy, Symbol};
91    use sim_lib_lang_genconf::{generative_registry, run_all_generated};
92
93    use crate::language_matrix;
94
95    fn closure_cx() -> Cx {
96        let mut cx = Cx::new(Arc::new(EagerPolicy), Arc::new(DefaultFactory));
97        sim_test_support::register_core_classes(&mut cx);
98        sim_test_support::register_f64_number_domain(&mut cx);
99        cx
100    }
101
102    #[test]
103    fn closure_registry_tracks_the_curated_language_matrix() {
104        let registry = generative_registry();
105        let matrix = language_matrix();
106        let mut names = BTreeSet::new();
107
108        assert_eq!(registry.len(), matrix.language_count());
109        assert_eq!(matrix.language_count(), 9);
110        for row in &registry {
111            assert!(
112                names.insert(row.language.clone()),
113                "duplicate generated row: {}",
114                row.language,
115            );
116            assert!(
117                matrix.row(&row.language).is_some(),
118                "{} row must stay in the curated matrix",
119                row.language,
120            );
121        }
122    }
123
124    #[test]
125    fn closure_registry_uses_live_language_codec_ids() {
126        let registry = generative_registry();
127
128        assert!(registry.iter().any(|row| {
129            row.language == Symbol::new("scheme")
130                && row.codec == Symbol::qualified("codec", "scheme-r7rs-small")
131        }));
132        assert!(registry.iter().any(|row| {
133            row.language == Symbol::new("common-lisp")
134                && row.codec == Symbol::qualified("codec", "common-lisp-lite")
135        }));
136        assert!(registry.iter().any(|row| {
137            row.language == Symbol::new("prolog") && row.codec == Symbol::qualified("codec", "lisp")
138        }));
139    }
140
141    #[test]
142    fn closure_reports_are_anchored_or_honest() {
143        let mut cx = closure_cx();
144        let reports = run_all_generated(&mut cx, 8);
145
146        assert_eq!(reports.len(), generative_registry().len());
147        for report in &reports {
148            if !report.landmark_reproduced() {
149                assert!(
150                    report.coverage_percent().is_none(),
151                    "{} must not publish unanchored coverage",
152                    report.language,
153                );
154            }
155        }
156        assert_eq!(language_matrix().language_count(), 9);
157    }
158}