Ion Schema 2.0 BNF-Style Grammar
This grammar is intended as a learning aid and is not authoritative.
Some limitations of this grammar are that it cannot accurately represent open content, that it excludes equivalent encodings of an Ion value (e.g. the symbol year could also be 'year'), that it does not describe a valid ISL regex string, and that it does not describe reserved words that cannot be used as a type name.
<ISL_VERSION_MARKER> ::= $ion_schema_2_0
<SCHEMA> ::= <ISL_VERSION_MARKER> [<HEADER>] <NAMED_TYPE_DEFINITION>... [<FOOTER>]
<HEADER> ::= schema_header::{ <HEADER_FIELD>... }
<HEADER_FIELD> ::= <IMPORTS_DECLARATION>
| <USER_RESERVED_FIELDS_DECLARATION>
<IMPORTS_DECLARATION> ::= imports: [ <IMPORT>... ],
<IMPORT> ::= <IMPORT_SCHEMA>
| <IMPORT_TYPE>
| <IMPORT_TYPE_ALIAS>
<IMPORT_SCHEMA> ::= { id: <SCHEMA_ID> }
<IMPORT_TYPE> ::= { id: <SCHEMA_ID>, type: <TYPE_NAME> }
<IMPORT_TYPE_ALIAS> ::= { id: <SCHEMA_ID>, type: <TYPE_NAME>, as: <TYPE_NAME> }
<USER_RESERVED_FIELDS_DECLARATION> ::= user_reserved_fields: { <USER_RESERVED_FIELDS_DECLARATION_FIELD>... }
<USER_RESERVED_FIELDS_DECLARATION_FIELD> ::= schema_header: [ <SYMBOL>... ],
| type: [ <SYMBOL>... ],
| schema_footer: [ <SYMBOL>... ],
<FOOTER> ::= schema_footer::{ }
<NAMED_TYPE_DEFINITION> ::= type::{ name: <TYPE_NAME>, <CONSTRAINT>... }
<INLINE_TYPE_DEFINITION> ::= { <CONSTRAINT>... }
<SCHEMA_ID> ::= <STRING>
| <SYMBOL>
<TYPE_NAME> ::= <SYMBOL>
<TYPE_ARGUMENT> ::= <TYPE_NAME>
| $null_or::<TYPE_NAME>
| <INLINE_TYPE_DEFINITION>
| $null_or::<INLINE_TYPE_DEFINITION>
| <IMPORT_TYPE>
| $null_or::<IMPORT_TYPE>
<OCCURS> ::= occurs: <INT>
| occurs: <RANGE_INT>
| occurs: optional
| occurs: required
<VARIABLY_OCCURRING_TYPE_ARGUMENT> ::= { <OCCURS>, <CONSTRAINT>... }
| <TYPE_ARGUMENT>
<NUMBER> ::= <DECIMAL>
| <FLOAT>
| <INT>
<EXCLUSIVITY> ::= exclusive::
| ""
<RANGE_INT> ::= range::[ <EXCLUSIVITY><INT>, <EXCLUSIVITY><INT> ]
| range::[ min, <EXCLUSIVITY><INT> ]
| range::[ <EXCLUSIVITY><INT>, max ]
<RANGE_NUMBER> ::= range::[ <EXCLUSIVITY><NUMBER>, <EXCLUSIVITY><NUMBER> ]
| range::[ min, <EXCLUSIVITY><NUMBER> ]
| range::[ <EXCLUSIVITY><NUMBER>, max ]
<RANGE_TIMESTAMP> ::= range::[ <EXCLUSIVITY><TIMESTAMP>, <EXCLUSIVITY><TIMESTAMP> ]
| range::[ min, <EXCLUSIVITY><TIMESTAMP> ]
| range::[ <EXCLUSIVITY><TIMESTAMP>, max ]
<RANGE_TIMESTAMP_PRECISION> ::= range::[ <EXCLUSIVITY><TIMESTAMP_PRECISION_VALUE>, <EXCLUSIVITY><TIMESTAMP_PRECISION_VALUE> ]
| range::[ min, <EXCLUSIVITY><TIMESTAMP_PRECISION_VALUE> ]
| range::[ <EXCLUSIVITY><TIMESTAMP_PRECISION_VALUE>, max ]
<CONSTRAINT> ::= <ALL_OF>
| <ANNOTATIONS>
| <ANY_OF>
| <BYTE_LENGTH>
| <CODEPOINT_LENGTH>
| <CONTAINER_LENGTH>
| <CONTAINS>
| <CONTENT>
| <ELEMENT>
| <EXPONENT>
| <FIELDS>
| <FIELD_NAMES>
| <IEEE745_FLOAT>
| <NOT>
| <ONE_OF>
| <ORDERED_ELEMENTS>
| <PRECISION>
| <REGEX>
| <TIMESTAMP_OFFSET>
| <TIMESTAMP_PRECISION>
| <TYPE>
| <VALID_VALUES>
<ALL_OF> ::= all_of: [ <TYPE_ARGUMENT>... ]
<ANNOTATIONS_MODIFIER> ::= required::
| closed::
<ANNOTATIONS> ::= annotations: <ANNOTATIONS_MODIFIER>... [ <SYMBOL>... ]
| annotations: <TYPE_ARGUMENT>
<ANY_OF> ::= any_of: [ <TYPE_ARGUMENT>... ]
<BYTE_LENGTH> ::= byte_length: <INT>
| byte_length: <RANGE_INT>
<CODEPOINT_LENGTH> ::= codepoint_length: <INT>
| codepoint_length: <RANGE_INT>
<CONTAINER_LENGTH> ::= container_length: <INT>
| container_length: <RANGE_INT>
<CONTAINS> ::= contains: [ <VALUE>... ]
<ELEMENT> ::= element: <TYPE_ARGUMENT>
| element: distinct::<TYPE_ARGUMENT>
<EXPONENT> ::= exponent: <INT>
| exponent: <RANGE_INT>
<FIELD> ::= <SYMBOL>: <VARIABLY_OCCURRING_TYPE_ARGUMENT>
<FIELDS> ::= fields: { <FIELD>... }
| fields: closed::{ <FIELD>... }
<FIELD_NAMES> ::= field_names: <TYPE_ARGUMENT>
| field_names: distinct::<TYPE_ARGUMENT>
<IEEE754_FLOAT> ::= ieee754_float: binary16
| ieee754_float: binary32
| ieee754_float: binary64
<NOT> ::= not: <TYPE_ARGUMENT>
<ONE_OF> ::= one_of: [ <TYPE_ARGUMENT>... ]
<ORDERED_ELEMENTS> ::= ordered_elements: [ <VARIABLY_OCCURRING_TYPE_ARGUMENT>... ]
<PRECISION> ::= precision: <INT>
| precision: <RANGE_INT>
<REGEX> ::= regex: <STRING>
| regex: i::<STRING>
| regex: m::<STRING>
| regex: i::m::<STRING>
<TIMESTAMP_OFFSET> ::= timestamp_offset: [ "[+|-]hh:mm"... ]
<TIMESTAMP_PRECISION_VALUE> ::= year
| month
| day
| minute
| second
| millisecond
| microsecond
| nanosecond
<TIMESTAMP_PRECISION> ::= timestamp_precision: <TIMESTAMP_PRECISION_VALUE>
| timestamp_precision: <RANGE_TIMESTAMP_PRECISION>
<TYPE> ::= type: <TYPE_ARGUMENT>
<UTF8_BYTE_LENGTH> ::= utf8_byte_length: <INT>
| utf8_byte_length: <RANGE_INT>
<VALID_VALUES> ::= valid_values: [ <VALUE_OR_RANGE>... ]
| valid_values: <RANGE_NUMBER>
| valid_values: <RANGE_TIMESTAMP>
<VALUE_OR_RANGE> ::= <VALUE>
| <RANGE_NUMBER>
| <RANGE_TIMESTAMP>