JXC Syntax

Input Encoding

All JXC source is expected to be valid UTF-8.

Syntax Rules

Note that the Syntax Diagrams are generated directly from this document.

{

value: Sequence[
    Whitespace<Optional>()
    Choice[
        Sequence[
            Sequence<Optional>[
                MatchGroupRef "annotation"
                # For non-container values, whitespace is required after the annotation
                Whitespace()
            ]
            Choice[
                MatchGroupRef "string"
                MatchGroupRef "string_raw"
                MatchGroupRef "string_base64"
                MatchGroupRef "string_datetime"
                MatchGroupRef "number"
                MatchGroupRef "float_literal"
                String "true"
                String "false"
                String "null"
            ]
        ]
        Sequence[
            Sequence<Optional>[
                MatchGroupRef "annotation"
                # For container values, whitespace is optional after the annotation
                Whitespace<Optional>()
            ]
            Choice[
                MatchGroupRef "object"
                MatchGroupRef "array"
                MatchGroupRef "expression"
            ]
        ]
    ]
    Whitespace<Optional>()
]

annotation: Sequence[
    Sequence<Optional>[
        Character '!'
        Whitespace<Optional>()
    ]
    MatchGroupRef "dotted_identifier"
    Sequence<Optional>[
        Character '<'
        Choice[
            Whitespace<Optional>()
            MatchGroupRef<OneOrMore> "annotation_inner"
        ]
        Character '>'
    ]
]

annotation_inner: Sequence[
    Whitespace<Optional>()
    Choice[
        MatchGroupRef "dotted_identifier"
        MatchGroupRef "string"
        MatchGroupRef "string_raw"
        MatchGroupRef "string_datetime"
        MatchGroupRef "number"
        MatchGroupRef "float_literal"
        String "true"
        String "false"
        String "null"
        Character '!'
        Character '*'
        Character '?'
        Character '|'
        Character '&'
        Character '='
        Character ','
        Sequence[
            Character '<'
            MatchGroupRef<ZeroOrMore> "annotation_inner"
            Character '>'
        ]
        Sequence[
            Character '('
            MatchGroupRef<ZeroOrMore> "annotation_inner"
            Character ')'
        ]
    ]
    Whitespace<Optional>()
]

object: Sequence[
    Character '{'
    Choice[
        Whitespace<Optional>()
        Sequence[
            Sequence<OneOrMore>[repeat[Choice[Character ',', MatchGroupRef "line_break"]], [
                Whitespace<Optional>()
                Choice[
                    MatchGroupRef<OneOrMore>[repeat('.'), "identifier_object_key"]
                    MatchGroupRef 'string'
                    MatchGroupRef 'number_object_key'
                    String "null"
                    String "true"
                    String "false"
                ]
                Whitespace<Optional>()
                Character ':'
                MatchGroupRef "value"
            ]]
            Choice<Optional>[
                Group{
                    name: 'trailing separator'
                    value: Sequence[
                        Choice[
                            Character ','
                            MatchGroupRef "line_break"
                        ]
                        Whitespace<Optional>()
                    ]
                }
            ]
        ]
    ]
    Character '}'
]

array: Sequence[
    Character '['
    Choice[
        Whitespace<Optional>()
        Sequence[
            Sequence<OneOrMore>[repeat[Choice[Character ',', MatchGroupRef "line_break"]], [
                MatchGroupRef "value"
            ]]
            Choice<Optional>[
                Group{
                    name: 'trailing separator'
                    value: Sequence[
                        Choice[
                            Character ','
                            MatchGroupRef "line_break"
                        ]
                        Whitespace<Optional>()
                    ]
                }
            ]
        ]
    ]
    Character ']'
]

expression: Sequence[
    Character '('
    Choice[
        Whitespace<Optional>()
        MatchGroupRef<OneOrMore> "expression_item"
    ]
    Character ')'
]

expression_item: Sequence[
    Whitespace<Optional>()
    Choice[
        MatchGroupRef "identifier"
        MatchGroupRef "string"
        MatchGroupRef "string_raw"
        MatchGroupRef "string_base64"
        MatchGroupRef "string_datetime"
        MatchGroupRef "number_unsigned"
        String "true"
        String "false"
        String "null"
        String "nan"
        String "inf"
        MatchGroupRef "expression_operator"
        MatchGroupRef "line_break"
        Character ','
        Character ':'
        Character '@'

        Sequence[
            Character '['
            Choice[
                MatchGroupRef<OneOrMore> "expression_item"
                Whitespace<Optional>()
            ]
            Character ']'
        ]

        Sequence[
            Character '{'
            Choice[
                MatchGroupRef<OneOrMore> "expression_item"
                Whitespace<Optional>()
            ]
            Character '}'
        ]

        Sequence[
            Character '('
            Choice[
                MatchGroupRef<OneOrMore> "expression_item"
                Whitespace<Optional>()
            ]
            Character ')'
        ]
    ]
    Whitespace<Optional>()
]

expression_operator: Choice[
    Character '|'
    Character '&'
    Character '!'
    Character '='
    Character '+'
    Character '-'
    Character '*'
    Character '/'
    Character '\\'
    Character '%'
    Character '^'
    Character '.'
    Character '?'
    Character '~'
    Character '<'
    Character '>'
    Character '`'
    Character ';'
]

dotted_identifier: Sequence[
    MatchGroupRef<OneOrMore>[
        repeat[Sequence[
            Whitespace<Optional>()
            Character '.'
            Whitespace<Optional>()
        ]]
        "identifier"
    ]
]

identifier: Sequence[
    Choice[
        CharacterRange['a', 'z']
        CharacterRange['A', 'Z']
        Character '_'
        Character '$'
    ]
    Choice<ZeroOrMore>[
        CharacterRange['a', 'z']
        CharacterRange['A', 'Z']
        CharacterRange['0', '9']
        Character '_'
        Character '$'
    ]
]

identifier_object_key: Sequence[
    Choice[
        CharacterRange['a', 'z']
        CharacterRange['A', 'Z']
        Character '_'
        Character '$'
        Character '*'
    ]
    Choice<ZeroOrMore>[
        CharacterRange['a', 'z']
        CharacterRange['A', 'Z']
        CharacterRange['0', '9']
        Character '_'
        Character '$'
        Character '*'
    ]
]

string: Sequence[
    Choice[
        Sequence[
            Character '"'
            Choice<ZeroOrMore>[
                CharacterRange{ exclusions: ['\\', '"'] }
                MatchGroupRef "string_escape_sequence"
            ]
            Character '"'
        ]
        Sequence[
            Character "'"
            Choice<ZeroOrMore>[
                CharacterRange{ exclusions: ['\\', "'"] }
                MatchGroupRef "string_escape_sequence"
            ]
            Character "'"
        ]
    ]
]

string_escape_sequence: Sequence[
    Character '\\'
    Choice[
        Sequence[ Character '"', Comment 'double quote' ]
        Sequence[ Character "'", Comment 'single quote' ]
        Sequence[ Character '\\', Comment 'backslash' ]
        Sequence[ Character '/', Comment 'forward slash' ]
        Sequence[ Character 'b', Comment 'backspace' ]
        Sequence[ Character 'f', Comment 'formfeed' ]
        Sequence[ Character 'n', Comment 'line break' ]
        Sequence[ Character 'r', Comment 'carriage return' ]
        Sequence[ Character 't', Comment 'horizontal tab' ]
        Sequence[
            Character 'x'
            MatchGroupRef<OneOrMore>[ repeat(2x), 'hex_digit' ]
            Comment 'one-byte character'
        ]
        Sequence[
            Character 'u'
            MatchGroupRef<OneOrMore>[ repeat(4x), 'hex_digit' ]
            Comment 'utf16-be codepoint'
        ]
        Sequence[
            Character 'U'
            MatchGroupRef<OneOrMore>[ repeat(8x), 'hex_digit' ]
            Comment 'utf32-be codepoint'
        ]
    ]
]

string_raw: Sequence[
    Character 'r'
    Choice[
        Sequence[
            Character '"'
            MatchGroupRef<Optional> "heredoc"
            Character '('
            Choice<ZeroOrMore>[
                CharacterRange()
            ]
            Character ')'
            MatchGroupRef<Optional> "heredoc"
            Character '"'
        ]
        Sequence[
            Character "'"
            MatchGroupRef<Optional> "heredoc"
            Character '('
            Choice<ZeroOrMore>[
                CharacterRange()
            ]
            Character ')'
            MatchGroupRef<Optional> "heredoc"
            Character '\''
        ]
    ]
]

heredoc: Sequence[
    Choice[
        CharacterRange[ 'a', 'z' ]
        CharacterRange[ 'A', 'Z' ]
        Character '_'
    ]
    Choice<ZeroOrMore>[repeat(1x, 14x), [
        CharacterRange[ 'a', 'z' ]
        CharacterRange[ 'A', 'Z' ]
        CharacterRange[ '0', '9' ]
        Character '_'
    ]]
    Comment '(max 15 characters)'
]

string_base64: Sequence[
    Choice[
        Sequence[
            String 'b64"'
            Sequence<ZeroOrMore>[
                MatchGroupRef "base64_digit"
            ]
            Character '"'
        ]
        Sequence[
            String "b64'"
            Sequence<ZeroOrMore>[
                MatchGroupRef "base64_digit"
            ]
            Character "'"
        ]
        Sequence[
            String 'b64"('
            Whitespace<Optional>()
            Sequence<ZeroOrMore>[
                MatchGroupRef "base64_digit"
                Whitespace<Optional>()
            ]
            String ')"'
        ]
        Sequence[
            String "b64'("
            Whitespace<Optional>()
            Sequence<ZeroOrMore>[
                MatchGroupRef "base64_digit"
                Whitespace<Optional>()
            ]
            String ")'"
        ]
    ]
    Comment "Digit count must be a multiple of 4"
]

string_datetime: Choice[
    Sequence[
        String 'dt"'
        MatchGroupRef "datetime_iso8601"
        Character '"'
    ]
    Sequence[
        String 'dt\''
        MatchGroupRef "datetime_iso8601"
        Character '\''
    ]
]

datetime_iso8601: Sequence[
    MatchGroupRef "date"
    Sequence<Optional>[
        Character 'T'
        MatchGroupRef "time"
        MatchGroupRef<Optional> "timezone"
    ]
]

date: Sequence[
    Group{
        name: 'Year'
        value: Sequence[
            Choice<Optional>[
                Character '+'
                Character '-'
            ]
            Sequence<OneOrMore>[repeat(4x, 5x), [ CharacterRange[ '0', '9' ] ]]
        ]
    }
    Character '-'
    Group{
        name: 'Month'
        value: Sequence[
            CharacterRange[ '0', '9' ]
            CharacterRange[ '0', '9' ]
        ]
    }
    Character '-'
    Group{
        name: 'Day'
        value: Sequence[
            CharacterRange[ '0', '9' ]
            CharacterRange[ '0', '9' ]
        ]
    }
]

time: Sequence[
    CharacterRange[ '0', '9' ]
    CharacterRange[ '0', '9' ]
    Character ':'
    CharacterRange[ '0', '9' ]
    CharacterRange[ '0', '9' ]
    Sequence<Optional>[
        Character ':'
        CharacterRange[ '0', '9' ]
        CharacterRange[ '0', '9' ]
    ]
    Sequence<Optional>[
        Character '.'
        Sequence<OneOrMore>[repeat(1x, 12x), [ CharacterRange[ '0', '9' ] ]]
    ]
]

timezone: Choice[
    Character 'Z'
    Sequence[
        Choice[
            Character '+'
            Character '-'
        ]
        CharacterRange[ '0', '9' ]
        CharacterRange[ '0', '9' ]
        Character ':'
        CharacterRange[ '0', '9' ]
        CharacterRange[ '0', '9' ]
    ]
]

number: Sequence[
    Choice<Optional>[
        Character '+'
        Character '-'
    ]
    MatchGroupRef "number_unsigned"
]

number_object_key: Sequence[
    Choice<Optional>[
        Character '+'
        Character '-'
    ]
    Choice[
        MatchGroupRef "number_unsigned_hex"
        MatchGroupRef "number_unsigned_bin"
        MatchGroupRef "number_unsigned_oct"
        Sequence[
            MatchGroupRef "number_unsigned_dec"
            MatchGroupRef<Optional> "exponent_positive"
        ]
    ]
]

number_unsigned: Sequence[
    Choice[
        MatchGroupRef "number_unsigned_hex"
        MatchGroupRef "number_unsigned_bin"
        MatchGroupRef "number_unsigned_oct"
        Sequence[
            MatchGroupRef "number_unsigned_dec"
            Choice<Optional>[
                MatchGroupRef "exponent_positive"
                MatchGroupRef "exponent_negative"
            ]
        ]
        Sequence[
            MatchGroupRef "number_unsigned_dec"
            Character '.'
            CharacterRange<OneOrMore>['0', '9']
            Choice<Optional>[
                MatchGroupRef "exponent_positive"
                MatchGroupRef "exponent_negative"
            ]
        ]
    ]
]

number_unsigned_dec: Sequence[
    CharacterRange['1', '9']
    Choice<ZeroOrMore>[
        CharacterRange['0', '9']
    ]
]

number_unsigned_hex: Sequence[
    Choice[
        String "0x"
        String "0X"
    ]
    MatchGroupRef<OneOrMore> "hex_digit"
]

number_unsigned_bin: Sequence[
    Choice[
        String "0b"
        String "0B"
    ]
    Choice<OneOrMore>[
        Character '0'
        Character '1'
    ]
]

number_unsigned_oct: Sequence[
    Choice[
        String "0o"
        String "0O"
    ]
    CharacterRange<OneOrMore>['0', '7']
]

number_suffix: Sequence[
    Choice[
        CharacterRange['a', 'z']
        CharacterRange['A', 'Z']
        Character '%'
    ]
    Choice<ZeroOrMore>[
        CharacterRange['a', 'z']
        CharacterRange['A', 'Z']
        CharacterRange['0', '9']
        Character '%'
    ]
    Comment "15 chars max"
]

exponent_positive: Sequence[
    Choice[
        Character 'e'
        Character 'E'
    ]
    Character<Optional> '+'
]

exponent_negative: Sequence[
    Choice[
        Character 'e'
        Character 'E'
    ]
    Character '-'
]

hex_digit: Choice[
    CharacterRange['a', 'f']
    CharacterRange['A', 'F']
    CharacterRange['0', '9']
]

base64_digit: Choice[
    CharacterRange['a', 'z']
    CharacterRange['A', 'Z']
    CharacterRange['0', '9']
    Character '+'
    Character '/'
    Character '='
]

float_literal: Choice[
    String "nan"
    Sequence[
        Choice<Optional>[
            Character '+'
            Character '-'
        ]
        String "inf"
    ]
]

whitespace_optional: Choice<ZeroOrMore>[
    Character ' '
    Character '\t'
    Character '\n'
    Character '\r'
]

whitespace: Choice<OneOrMore>[
    Character ' '
    Character '\t'
    Character '\n'
    Character '\r'
]

line_break: Choice<OneOrMore>[
    Character '\n'
    Character '\r'
]

}