1use crate::messages::Refusal;
25
26pub use vla_lang::projection::{Projection, Window};
27
28#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30pub struct Seam {
31 pub name: &'static str,
33 pub entrance: &'static str,
36 pub oracle: &'static str,
38 pub implementations: &'static [&'static str],
41 pub deferred_to: &'static str,
43}
44
45pub const SEAMS: [Seam; 6] = [
47 Seam {
48 name: "sentences",
49 entrance: "a phrasebook file (.vla) with its test: proofs, loaded through api::vocab_gate",
50 oracle: "frazaro prove passes every proof; the translate and refusal goldens hold",
51 implementations: &["the phrasebooks a door loads, english.vla first"],
52 deferred_to: "",
53 },
54 Seam {
55 name: "paragraphs",
56 entrance: "a library of sentences with named slots, imported by a Use sentence",
57 oracle: "the build golden, and the stamp hashing every file used",
58 implementations: &[],
59 deferred_to: "G-USE",
60 },
61 Seam {
62 name: "engines",
63 entrance: "an implementation of kernel::Engine under a head-table symbol",
64 oracle: "a proof file of its kind, with clingo beside it where it applies",
65 implementations: &[],
66 deferred_to: "PORT.9",
67 },
68 Seam {
69 name: "formats and hosts",
70 entrance: "an implementation of reflect::Source to read, a writer beside it, and a kernel::HostProfile per door",
71 oracle: "the reflect, diff and audit goldens for a reader; the build golden for a writer",
72 implementations: &["xlsx (OOXML), read and written", "ods (OpenDocument), read"],
73 deferred_to: "",
74 },
75 Seam {
76 name: "projections",
77 entrance: "an implementation of vla_lang::projection::Projection",
78 oracle: "a view golden per projection",
79 implementations: &[
80 "grid, the view record of one window (view::Grid)",
81 "values, the view record less its formula rows (view::ValueGrid)",
82 ],
83 deferred_to: "",
84 },
85 Seam {
86 name: "functions",
87 entrance: "a function registered into vla_lang::calc::Library, with the fixture a host saved that shows it (excel::library)",
88 oracle: "the recalc golden: the fixture's cached values agree (check_recalc_golden.ps1)",
89 implementations: &[
90 "the language's fourteen day-one functions (vla_lang::calc::library)",
91 "Excel's library, the declared subset by measurement (excel::SUBSET)",
92 ],
93 deferred_to: "",
94 },
95];
96
97pub fn seams() -> &'static [Seam] {
99 &SEAMS
100}
101
102#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub struct Format {
105 pub name: &'static str,
106 pub extension: &'static str,
107 pub reads: bool,
108 pub writes: bool,
109}
110
111pub const FORMATS: [Format; 2] = [
114 Format {
115 name: "OOXML",
116 extension: "xlsx",
117 reads: true,
118 writes: true,
119 },
120 Format {
121 name: "OpenDocument",
122 extension: "ods",
123 reads: true,
124 writes: false,
125 },
126];
127
128pub trait Engine {
134 type Table;
136 fn head(&self) -> &str;
138 fn proof_kind(&self) -> &str;
140 fn run(&self, tables: &[Self::Table]) -> Result<Self::Table, Refusal>;
142}
143
144#[derive(Clone, Copy, Debug, PartialEq, Eq)]
147pub struct HostProfile {
148 pub door: &'static str,
149 pub forms: &'static [&'static str],
151 pub scaffold: &'static [&'static str],
153 pub refuses_with: &'static str,
155}
156
157pub const FILE_DOOR: HostProfile = HostProfile {
163 door: "file",
164 forms: &[
165 "at-line",
166 "begin",
167 "dim",
168 "on-error",
169 "label",
170 "exit-sub",
171 "exit-function",
172 "set!",
173 "if",
174 ".",
175 ],
176 scaffold: &["vla-report-error", "vlaensuresheet"],
177 refuses_with: "build-not-representable",
178};
179
180pub const HOST_PROFILES: [HostProfile; 1] = [FILE_DOOR];
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use crate::headtable;
189 use crate::reflect;
190
191 const FIXTURE_XLSX: &[u8] = include_bytes!("../../scripts/reflect/fixture.xlsx");
192 const FIXTURE_ODS: &[u8] = include_bytes!("../../scripts/reflect/opendocument.ods");
193
194 #[test]
195 fn six_seams_each_with_an_entrance_and_an_oracle() {
196 assert_eq!(seams().len(), 6);
197 let names: Vec<&str> = seams().iter().map(|s| s.name).collect();
198 assert_eq!(
199 names,
200 [
201 "sentences",
202 "paragraphs",
203 "engines",
204 "formats and hosts",
205 "projections",
206 "functions"
207 ]
208 );
209 for s in seams() {
210 assert!(!s.entrance.is_empty(), "{} names no entrance", s.name);
211 assert!(!s.oracle.is_empty(), "{} names no oracle", s.name);
212 assert!(
213 !s.implementations.is_empty() || !s.deferred_to.is_empty(),
214 "{} has neither an implementation nor the item that lands one",
215 s.name
216 );
217 }
218 }
219
220 #[test]
221 fn the_engines_seam_is_empty_today_and_the_projections_seam_has_its_grid_and_values() {
222 let engines = seams().iter().find(|s| s.name == "engines").unwrap();
223 assert!(engines.implementations.is_empty());
224 assert_eq!(engines.deferred_to, "PORT.9");
225 let projections = seams().iter().find(|s| s.name == "projections").unwrap();
226 assert_eq!(projections.implementations.len(), 2);
227 assert_eq!(projections.deferred_to, "");
228 assert_eq!(crate::view::Grid::default().name(), "grid");
229 assert!(projections.implementations[0].starts_with("grid"));
230 assert_eq!(crate::view::ValueGrid::default().name(), "values");
231 assert!(projections.implementations[1].starts_with("values"));
232 let paragraphs = seams().iter().find(|s| s.name == "paragraphs").unwrap();
233 assert_eq!(paragraphs.deferred_to, "G-USE");
234 }
235
236 #[test]
237 fn the_formats_registry_matches_the_readers_and_the_writer() {
238 assert_eq!(FORMATS.len(), 2);
239 assert!(reflect::open(FIXTURE_XLSX, "fixture.xlsx").is_ok());
240 assert!(reflect::open(FIXTURE_ODS, "opendocument.ods").is_ok());
241 let readers: Vec<&str> = FORMATS
242 .iter()
243 .filter(|f| f.reads)
244 .map(|f| f.extension)
245 .collect();
246 assert_eq!(readers, ["xlsx", "ods"]);
247 let writers: Vec<&str> = FORMATS
248 .iter()
249 .filter(|f| f.writes)
250 .map(|f| f.extension)
251 .collect();
252 assert_eq!(writers, ["xlsx"], "the one writer is the OOXML writer");
253 let formats = seams()
254 .iter()
255 .find(|s| s.name == "formats and hosts")
256 .unwrap();
257 assert_eq!(formats.implementations.len(), FORMATS.len());
258 }
259
260 #[test]
261 fn the_file_door_holds_only_core_forms_and_refuses_from_the_catalogue() {
262 assert_eq!(HOST_PROFILES.len(), 1);
263 assert_eq!(FILE_DOOR.door, "file");
264 for sym in FILE_DOOR.forms {
265 let canonical = headtable::resolve_head_alias(sym);
266 assert!(
267 headtable::row(&canonical).is_some(),
268 "{sym} is not a form of the head table"
269 );
270 }
271 for call in FILE_DOOR.scaffold {
272 assert!(
273 headtable::row(call).is_none(),
274 "{call} is a scaffold call, not a core form"
275 );
276 }
277 assert_eq!(FILE_DOOR.refuses_with, "build-not-representable");
278 }
279
280 #[test]
281 fn the_projection_trait_is_the_language_s() {
282 let w: vla_lang::projection::Window = Window {
284 sheet: "Model".to_string(),
285 range: crate::sheet::parse_a1_range("A1:F20").unwrap(),
286 };
287 assert_eq!(w.range.cells(), 120);
288 }
289}