Bosque Object Notation (BSQON) is a combination of a type-system based language for describing data formats (or configuration files) and a specialized literal format.
The specification language is structured as a programming language type system. This design technical report provides a powerful set of features for describing complex data formats and structures and, just like any other programming language, enables us to compose, package, type-check, version, and provide iDE support for these specifications. This language provides a rich set of builtin types and type system feature that are specifically designed to support the needs of data formats and serialization (and AI or human agents working with them). It goes further by providing bosque expression language for defining constraints and default values that cannot be expressed in a simple type system. This expression language is unique as, it is a regularized programming language, and is thus amenable to static analysis and verification -- we are targeting fuzzing, mocking, and version checking on our roadmap.
The literal format language is designed to be easily human, AI, and machine processable. The format supports nice to have features, like comments, flexible syntactic decorations to ease reading/writing them, and efficient parsing. Further, in conjunction with the type language, we can generate parsers, command completion, checkers, and other IDE support tools automatically! This literal format provides specialized formats for all the builtin types and convenient notation for custom designed types -- providing in a readable format that is resistant to typos, missing fields, and other common sources of errors that occur in literal/config data objects.
%%%%
%% Data Specification
type Identifier = CString of /[A-Za-z][A-Za-z0-9_]{0-9}/c;
type CUSIP = CString of /[0-9]{6}[0-9A-Z]{3}/c;
type Quantity = BigNat;
entity SaleOrder {
field id: Identifier;
field instrument: CUSIP;
field quantity: Quantity;
}
entity DaySalesSummary {
field available: Quantity;
field startAvailable: Quantity;
field orders: List<SaleOrder>;
validate orders.unique(pred(a, b) => a.id !== b.id);
validate startAvailable - orders.sumOf<Quantity>(fn(a) => a.quantity) == available;
}
%%%%
%% Literal
DaySalesSummary{
available: 800N<Quantity>,
startAvailable: 1000N<Quantity>,
orders: [
SaleOrder{ 'A1'<Identifier>, '123456789'<CUSIP>, 100N<Quantity> },
SaleOrder{ 'A2'<Identifier>, '123456789'<CUSIP>, 100N<Quantity> }
]
}
%%%%
%% Literal (with errors)
DaySalesSummary{
available: 900N<Quantity>, %% fails startAvailable - orders check
startAvailable: 1000.5, %% fails type check
orders: [
SaleOrder{ 'A1'<Identifier>, '123$56789'<CUSIP>, 100N<Quantity> }, %% fails CUSIP format check
SaleOrder{ 'A1'<Identifier>, '123456789'<CUSIP>, 100N<Quantity> } %% fails invariant on unique id
]
}