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>