/* DTOB-Doc */
/* Delineated Trinary Over Binary for Documents */

data_trit    ::= "00" | "01" | "10"
pad          ::= "11"
data_payload ::= { data_trit } { pad }    /* padded to byte boundary */
ctrl_word    ::= "11" "0" code(13 bits)     /* always two bytes; bit 5 reserved */

/*=========================*/
/* OPCODES
/*=========================*/

/* built-in codes and IEEE 754 floating points (0-7) */
open         ::= ctrl_word("0000000 00000000") /* 0  */
close_arr    ::= ctrl_word("0000000 00000001") /* 1  */  /* structs and lists */
close_kv     ::= ctrl_word("0000000 00000010") /* 2  */  /* enum    */
close_types  ::= ctrl_word("0000000 00000011") /* 3  */
uqt          ::= ctrl_word("0000000 00000100") /* 4  */  /* unimplemented */
raw          ::= ctrl_word("0000000 00000101") /* 5  */
float        ::= ctrl_word("0000000 00000110") /* 6  */
double       ::= ctrl_word("0000000 00000111") /* 7  */

/* little-endian integer types (8-15). bit 2 flag: 0=signed, 1=unsigned */
int8_t       ::= ctrl_word("0000000 00001000") /* 8  */
int16_t      ::= ctrl_word("0000000 00001001") /* 9  */
int32_t      ::= ctrl_word("0000000 00001010") /* 10 */
int64_t      ::= ctrl_word("0000000 00001011") /* 11 */
uint8_t      ::= ctrl_word("0000000 00001100") /* 12 */
uint16_t     ::= ctrl_word("0000000 00001101") /* 13 */
uint32_t     ::= ctrl_word("0000000 00001110") /* 14 */
uint64_t     ::= ctrl_word("0000000 00001111") /* 15 */

/* custom codes (16-8190) — must be declared in types header */
custom_code  ::= ctrl_word("000000 00010000") /* 16   */
             |   ...
             |   ctrl_word("011111 11111110") /* 8190 */

/* for analogue mediums */
blast        ::= ctrl_word("011111 11111111") /* 8191 */

/*=========================*/
/* TYPEDEF RULES
/*=========================*/


/* type opcodes — primitives or other custom types that can appear in an enum */
type_opcode  ::= c_int | c_float | raw | custom_code

/* types header — each type def is enclosed in open ... close */
enum_def     ::= open custom_code data_payload [ type_opcode { type_opcode } ] close_kv
struct_def   ::= open custom_code data_payload type_opcode { type_opcode } close_arr
custom_def   ::= enum_def | struct_def
types_header ::= open { custom_def } close_types

/* values */
c_int        ::= int8_t | int16_t | int32_t | int64_t
             |   uint8_t | uint16_t | uint32_t | uint64_t
c_float      ::= float | double /* mandated 32 and 64 bits respectively */

/* custom value encoding rules:
 *   nullable (0 opcodes):     custom_code
 *   one-type enum:            custom_code [data_payload]
 *   multi-type enum:          custom_code type_opcode [data_payload]
 *   struct:                   custom_code open { type_opcode data_payload } close_arr
 */
typed_data   ::= (raw | c_int | c_float) data_payload
             |   custom_code [ type_opcode ] [ data_payload ]
             |   custom_code open { type_opcode [ data_payload ] } close_arr
value        ::= typed_data | array | kv_set
array        ::= open { value } close_arr
kv_set       ::= open { raw data_payload value } close_kv

/* top-level document — every document starts with the magic number "13032026" in ASCII */
magic        ::= %x31.33.30.33.32.30.32.36  /* "13032026" — raw bytes, not trit-encoded */
dtob         ::= magic open [ types_header ] { value } (close_arr | close_kv)
             |   magic open types_header close_types
