Validate BAST documents against the meta-schema at compile time

Resolves review #003 finding M3.

- Add bast_meta::validate_bast_doc and call it from AlkTypeEngine::compile
  before parsing. Malformed annotations (unknown endian/encoding strings,
  non-integer align/maxLength, missing required properties) now surface as
  AlkTypeError::Schema instead of being silently tolerated by the parser.
- Align the meta-schema TypeRef with the parser: allow inline struct/union/
  enum as TypeRefs (the parser and builder already accepted them; the
  meta-schema and spec did not). Update bast-format.md TypeRef table and
  the BastType doc comment to the seven-form vocabulary.

Verification: cargo test --release (410 pass), cargo clippy --all-targets
-- -D warnings (clean), cargo doc --no-deps (clean), cargo build --target
wasm32-unknown-unknown --release (clean).
This commit is contained in:
deepseek-v4-pro committed 2026-08-16 08:54:57 +00:00
1 parent e5c7cc1ca2
commit 230345a867
4 files changed
+155 -6

No files matched your search

+66
View File
@@ -126,6 +126,7 @@ impl AlkTypeEngine {
mode: LayoutMode,
json_schema: Option<&Value>,
) -> Result<Self, AlkTypeError> {
crate::bast_meta::validate_bast_doc(bast_doc)?;
let doc = BastDoc::new(bast_doc, root_name)?;
let root_def = doc.root_def();
let struct_node = match root_def.kind() {
@@ -913,6 +914,71 @@ mod tests {
assert!(matches!(err, AlkTypeError::Schema(_)), "got {err:?}");
}
#[test]
fn compile_rejects_unknown_endian_annotation() {
let doc = json!({
"$defs": {
"S": {
"kind": "struct",
"endian": "middle",
"fields": [ { "name": "id", "kind": "uint32" } ]
}
}
});
let err = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed, None).unwrap_err();
assert!(matches!(err, AlkTypeError::Schema(_)), "got {err:?}");
}
#[test]
fn compile_rejects_unknown_encoding_annotation() {
let doc = json!({
"$defs": {
"S": {
"kind": "struct",
"fields": [
{ "name": "blob", "kind": "bytes", "encoding": "sideways" }
]
}
}
});
let err = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed, None).unwrap_err();
assert!(matches!(err, AlkTypeError::Schema(_)), "got {err:?}");
}
#[test]
fn compile_rejects_non_integer_align() {
let doc = json!({
"$defs": {
"S": {
"kind": "struct",
"align": "wide",
"fields": [ { "name": "id", "kind": "uint32" } ]
}
}
});
let err = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed, None).unwrap_err();
assert!(matches!(err, AlkTypeError::Schema(_)), "got {err:?}");
}
#[test]
fn compile_accepts_inline_struct_field() {
let doc = json!({
"$defs": {
"S": {
"kind": "struct",
"fields": [
{ "name": "inner", "kind": {
"kind": "struct",
"fields": [ { "name": "x", "kind": "uint16" } ]
} }
]
}
}
});
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed, None).expect("compile");
assert_eq!(engine.mode(), LayoutMode::Packed);
}
#[test]
fn debug_formats_without_panicking() {
let doc = fixed_struct_doc();