use crate::messages::Refusal;
use crate::sheet::{A1Range, Workbook};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Seam {
pub name: &'static str,
pub entrance: &'static str,
pub oracle: &'static str,
pub implementations: &'static [&'static str],
pub deferred_to: &'static str,
}
pub const SEAMS: [Seam; 5] = [
Seam {
name: "sentences",
entrance: "a phrasebook file (.vla) with its test: proofs, loaded through api::vocab_gate",
oracle: "frazaro prove passes every proof; the translate and refusal goldens hold",
implementations: &["the phrasebooks a door loads, english.vla first"],
deferred_to: "",
},
Seam {
name: "paragraphs",
entrance: "a library of sentences with named slots, imported by a Use sentence",
oracle: "the build golden, and the stamp hashing every file used",
implementations: &[],
deferred_to: "G-USE",
},
Seam {
name: "engines",
entrance: "an implementation of kernel::Engine under a head-table symbol",
oracle: "a proof file of its kind, with clingo beside it where it applies",
implementations: &[],
deferred_to: "PORT.9",
},
Seam {
name: "formats and hosts",
entrance: "an implementation of reflect::Source to read, a writer beside it, and a kernel::HostProfile per door",
oracle: "the reflect, diff and audit goldens for a reader; the build golden for a writer",
implementations: &["xlsx (OOXML), read and written", "ods (OpenDocument), read"],
deferred_to: "",
},
Seam {
name: "projections",
entrance: "an implementation of kernel::Projection",
oracle: "a view golden per projection",
implementations: &[],
deferred_to: "KERNEL.4",
},
];
pub fn seams() -> &'static [Seam] {
&SEAMS
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Format {
pub name: &'static str,
pub extension: &'static str,
pub reads: bool,
pub writes: bool,
}
pub const FORMATS: [Format; 2] = [
Format {
name: "OOXML",
extension: "xlsx",
reads: true,
writes: true,
},
Format {
name: "OpenDocument",
extension: "ods",
reads: true,
writes: false,
},
];
pub trait Engine {
type Table;
fn head(&self) -> &str;
fn proof_kind(&self) -> &str;
fn run(&self, tables: &[Self::Table]) -> Result<Self::Table, Refusal>;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Window {
pub sheet: String,
pub range: A1Range,
}
pub trait Projection {
fn name(&self) -> &str;
fn project(&self, model: &Workbook, window: &Window, out: &mut dyn FnMut(&str));
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct HostProfile {
pub door: &'static str,
pub forms: &'static [&'static str],
pub scaffold: &'static [&'static str],
pub refuses_with: &'static str,
}
pub const FILE_DOOR: HostProfile = HostProfile {
door: "file",
forms: &[
"at-line",
"begin",
"dim",
"on-error",
"label",
"exit-sub",
"exit-function",
"set!",
"if",
".",
],
scaffold: &["vla-report-error", "vlaensuresheet"],
refuses_with: "build-not-representable",
};
pub const HOST_PROFILES: [HostProfile; 1] = [FILE_DOOR];
#[cfg(test)]
mod tests {
use super::*;
use crate::headtable;
use crate::reflect;
const FIXTURE_XLSX: &[u8] = include_bytes!("../../scripts/reflect/fixture.xlsx");
const FIXTURE_ODS: &[u8] = include_bytes!("../../scripts/reflect/opendocument.ods");
#[test]
fn five_seams_each_with_an_entrance_and_an_oracle() {
assert_eq!(seams().len(), 5);
let names: Vec<&str> = seams().iter().map(|s| s.name).collect();
assert_eq!(
names,
[
"sentences",
"paragraphs",
"engines",
"formats and hosts",
"projections"
]
);
for s in seams() {
assert!(!s.entrance.is_empty(), "{} names no entrance", s.name);
assert!(!s.oracle.is_empty(), "{} names no oracle", s.name);
assert!(
!s.implementations.is_empty() || !s.deferred_to.is_empty(),
"{} has neither an implementation nor the item that lands one",
s.name
);
}
}
#[test]
fn the_engines_and_projections_seams_are_named_and_empty_today() {
let engines = seams().iter().find(|s| s.name == "engines").unwrap();
assert!(engines.implementations.is_empty());
assert_eq!(engines.deferred_to, "PORT.9");
let projections = seams().iter().find(|s| s.name == "projections").unwrap();
assert!(projections.implementations.is_empty());
assert_eq!(projections.deferred_to, "KERNEL.4");
let paragraphs = seams().iter().find(|s| s.name == "paragraphs").unwrap();
assert_eq!(paragraphs.deferred_to, "G-USE");
}
#[test]
fn the_formats_registry_matches_the_readers_and_the_writer() {
assert_eq!(FORMATS.len(), 2);
assert!(reflect::open(FIXTURE_XLSX, "fixture.xlsx").is_ok());
assert!(reflect::open(FIXTURE_ODS, "opendocument.ods").is_ok());
let readers: Vec<&str> = FORMATS
.iter()
.filter(|f| f.reads)
.map(|f| f.extension)
.collect();
assert_eq!(readers, ["xlsx", "ods"]);
let writers: Vec<&str> = FORMATS
.iter()
.filter(|f| f.writes)
.map(|f| f.extension)
.collect();
assert_eq!(writers, ["xlsx"], "the one writer is the OOXML writer");
let formats = seams()
.iter()
.find(|s| s.name == "formats and hosts")
.unwrap();
assert_eq!(formats.implementations.len(), FORMATS.len());
}
#[test]
fn the_file_door_holds_only_core_forms_and_refuses_from_the_catalogue() {
assert_eq!(HOST_PROFILES.len(), 1);
assert_eq!(FILE_DOOR.door, "file");
for sym in FILE_DOOR.forms {
let canonical = headtable::resolve_head_alias(sym);
assert!(
headtable::row(&canonical).is_some(),
"{sym} is not a form of the head table"
);
}
for call in FILE_DOOR.scaffold {
assert!(
headtable::row(call).is_none(),
"{call} is a scaffold call, not a core form"
);
}
assert_eq!(FILE_DOOR.refuses_with, "build-not-representable");
}
#[test]
fn a_window_is_one_sheet_and_one_rectangle() {
let w = Window {
sheet: "Model".to_string(),
range: A1Range {
top: 1,
left: 1,
bottom: 20,
right: 6,
},
};
assert_eq!(w.range.cells(), 120);
assert_eq!(w.sheet, "Model");
}
}