Skip to main content

sim_lib_lang_lua/
matrix_row.rs

1//! Lua conformance matrix row.
2
3use sim_kernel::Symbol;
4use sim_lib_standard_core::{
5    LanguageRow, LanguageRowBuilder, SourceConformanceCase, SourceConformanceCaseKind,
6    SourceExpectation,
7};
8
9use crate::{
10    lua_core_profile, lua_full_runtime_fidelity_symbol, lua_lowering_symbol, lua_reader_symbol,
11};
12
13/// Builds the Lua core matrix row.
14pub fn lua_core_matrix_row() -> LanguageRow {
15    LanguageRowBuilder::new(Symbol::new("lua"), lua_core_profile())
16        .with_cases(lua_core_source_cases())
17        .build()
18}
19
20/// Minimal source cases for the Lua core matrix row.
21pub fn lua_core_source_cases() -> Vec<SourceConformanceCase> {
22    vec![
23        SourceConformanceCase {
24            symbol: Symbol::qualified("test/lua-core", "profile-declared"),
25            organ: lua_reader_symbol(),
26            source_name: "profile.sim".to_owned(),
27            source: "profile".to_owned(),
28            kind: SourceConformanceCaseKind::DescriptorOnly,
29            expectation: SourceExpectation::LowersTo(lua_core_profile_display()),
30            affects_badge: Some(Symbol::qualified("standard", "partial")),
31        },
32        observed("load-source", "return load('return 1 + 2')()", "3"),
33        observed(
34            "closure-upvalue",
35            "local n = 0 local f = function() n = n + 1 return n end return f() + f()",
36            "3",
37        ),
38        observed(
39            "metatable-vector",
40            "local mt = { __add = function(a, b) return { x = a.x + b.x, y = a.y + b.y } end } local a = setmetatable({ x = 2, y = 4 }, mt) local b = { x = 3, y = 5 } local c = a + b return c.x + c.y",
41            "14",
42        ),
43        observed(
44            "coroutine-producer",
45            "local co = coroutine.create(function() return 1 end) return select(2, coroutine.resume(co))",
46            "1",
47        ),
48        observed(
49            "string-patterns",
50            "local out, n = string.gsub('aba', 'a', 'x') return out .. ':' .. n",
51            "xbx:2",
52        ),
53        expected_gap(
54            "bytecode",
55            "return string.dump(function() end)",
56            "lua.bytecode.dump",
57            "Lua bytecode dumping is explicitly unsupported",
58        ),
59        expected_gap(
60            "debug-hook",
61            "return debug.sethook(function() end, 'l')",
62            "lua.debug.sethook",
63            "Lua debug hooks are outside the safe debug subset",
64        ),
65        expected_gap(
66            "c-api",
67            "return package.loadlib('liblua.so', 'luaopen_demo')",
68            "lua.c-api",
69            "Lua C API package loading is outside the source runtime",
70        ),
71    ]
72}
73
74fn observed(name: &str, source: &str, expected: &str) -> SourceConformanceCase {
75    SourceConformanceCase {
76        symbol: Symbol::qualified("test/lua-core", name),
77        organ: lua_lowering_symbol(),
78        source_name: format!("{name}.lua"),
79        source: source.to_owned(),
80        kind: SourceConformanceCaseKind::Observed,
81        expectation: SourceExpectation::LowersTo(expected.to_owned()),
82        affects_badge: Some(lua_full_runtime_fidelity_symbol()),
83    }
84}
85
86fn expected_gap(name: &str, source: &str, code: &str, reason: &str) -> SourceConformanceCase {
87    SourceConformanceCase {
88        symbol: Symbol::qualified("test/lua-core", name),
89        organ: lua_lowering_symbol(),
90        source_name: format!("{name}.lua"),
91        source: source.to_owned(),
92        kind: SourceConformanceCaseKind::Observed,
93        expectation: SourceExpectation::ExpectedGap {
94            code: Symbol::new(code),
95            reason: reason.to_owned(),
96        },
97        affects_badge: Some(lua_full_runtime_fidelity_symbol()),
98    }
99}
100
101fn lua_core_profile_display() -> String {
102    let profile = lua_core_profile();
103    format!(
104        "profile:{} reader:{} lowering:{}",
105        profile.symbol, profile.reader, profile.lowering
106    )
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn lua_core_matrix_row_language_symbol_is_lua() {
115        let row = lua_core_matrix_row();
116
117        assert_eq!(row.language, Symbol::new("lua"));
118        assert!(!row.is_empty());
119        assert_eq!(row.cases.len(), 9);
120        assert!(matches!(
121            row.cases[0].expectation,
122            SourceExpectation::LowersTo(_)
123        ));
124        assert!(matches!(
125            row.cases[1].expectation,
126            SourceExpectation::LowersTo(_)
127        ));
128        assert!(
129            row.cases
130                .iter()
131                .any(|case| matches!(case.expectation, SourceExpectation::ExpectedGap { .. }))
132        );
133    }
134}