1use 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
13pub 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
20pub 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}