wcandillon/language-jsoniq

View on GitHub
grammars/jsoniq.cson

Summary

Maintainability
Test Coverage
name: "JSONiq"
scopeName: "source.jsoniq"
fileTypes: [
    "jq"
]
firstLineMatch: "^\\bjsoniq\\s+version\\b.*"
foldingStartMarker: "^\\s*(<[^!?%/](?!.+?(/>|</.+?>))|<[!%]--(?!.+?--%?>)|<%[!]?(?!.+?%>))|(declare|.*\\{\\s*(//.*)?$)"
foldingStopMarker:  "^\\s*(</[^>]+>|[/%]>|-->)\\s*$|(.*\\}\\s*;?\\s*|.*;)"
patterns: [include: "#main"]

repository:

    # Grammar's entry-point
    main:
        patterns: [
            {include: "#EmbeddedXQuery"}
            {include: "#Pragma"}
            {include: "#XMLComment"}
            {include: "#CDATA"}
            {include: "#PredefinedEntityRef"}
            {include: "#CharRef"}
            {include: "#Comments"}
            {include: "#String"}
            {include: "#Annotation"}
            {include: "#AbbrevForwardStep"}
            {include: "#Variable"}
            {include: "#Numbers"}
            {include: "#Keywords"}
            {include: "#EQName"}
            {include: "#Symbols"}
            {include: "#OpenTag"}
            {include: "#CloseTag"}
        ]

    AbbrevForwardStep:
        name: "support.type.jsoniq"
        match: "(@)(?:\\*\\s|(?:[-_a-zA-Z0-9][-._a-zA-Z0-9]*:)?[-_a-zA-Z0-9][-._a-zA-Z0-9]*)"
        captures:
            1: name: "punctuation.definition.type.jsoniq"

    Annotation:
        name:  "meta.declaration.annotation.jsoniq"
        match: "(%+)((?:[-_a-zA-Z0-9][-._a-zA-Z0-9]*:)?[-_a-zA-Z0-9][-._a-zA-Z0-9]*)"
        captures:
            1: name: "punctuation.definition.annotation.jsoniq"
            2: name: "entity.name.annotation.jsoniq"

    CDATA:
        name:  "string.unquoted.cdata.jsoniq"
        begin: "<!\\[CDATA\\["
        end:   "\\]\\]>"
        beginCaptures: 0: name: "punctuation.definition.string.begin.jsoniq"
        endCaptures:   0: name: "punctuation.definition.string.end.jsoniq"

    CharRef:
        name: "constant.character.entity.jsoniq"
        match: "(&#)([0-9]+|x[0-9A-Fa-f]+)(;)"
        captures:
            1: name: "punctuation.definition.entity.begin.jsoniq"
            2: name: "entity.name.entity.other.jsoniq"
            3: name: "punctuation.definition.entity.end.jsoniq"

    CloseTag:
        name:  "meta.tag.closetag.jsoniq"
        match: "(<\\/)((?:[-_a-zA-Z0-9][-._a-zA-Z0-9]*:)?[-_a-zA-Z0-9][-_a-zA-Z0-9]*)\\s*(>)"
        captures:
            1: name: "punctuation.definition.tag.begin.jsoniq"
            2: name: "entity.name.tag.localname.jsoniq"
            3: name: "punctuation.definition.tag.end.jsoniq"

    Comments:
        patterns: [{
            name:  "comment.block.doc.jsoniq"
            begin: "\\(:~"
            end:   ":\\)"
            beginCaptures: 0: name: "punctuation.definition.comment.begin.jsoniq"
            endCaptures:   0: name: "punctuation.definition.comment.end.jsoniq"
            patterns: [{
                name: "constant.language.jsoniq"
                match: "(@)[a-zA-Z0-9_\\.\\-]+"
                captures:
                    1: name: "punctuation.definition.jsoniq"
            }]
        },{
            # <? … ?>
            name:  "comment.block.jsoniq"
            begin: "<\\?"
            end:   "\\?>"
            beginCaptures: 0: name: "punctuation.definition.comment.begin.jsoniq"
            endCaptures:   0: name: "punctuation.definition.comment.end.jsoniq"
        },{
            # (: … :)
            name:  "comment.block.jsoniq"
            begin: "\\(:"
            end:   ":\\)"
            beginCaptures: 0: name: "punctuation.definition.comment.begin.jsoniq"
            endCaptures:   0: name: "punctuation.definition.comment.end.jsoniq"
        }]

    EmbeddedXQuery:
        begin: "^(?=xquery\\s+version\\s+)"
        end:   "\\z"
        contentName: "source.embedded.xq"
        patterns: [include: "source.xq"]

    EQName:
        name: "support.function.eqname.jsoniq"
        match: "(?:[-_a-zA-Z0-9][-._a-zA-Z0-9]*:)?[-_a-zA-Z0-9][-_a-zA-Z0-9]*(?=\\s*\\()"

    Keywords:
        patterns: [{
            name: "constant.language.${1:/downcase}.jsoniq"
            match: "\\b(NaN|null)\\b"
        },{
            name: "constant.language.boolean.logical.$1.jsoniq"
            match: "\\b(true|false)\\b"
        },{
            name: "storage.type.$1.jsoniq"
            match: "\\b(function|let)\\b"
        },{
            # FIXME: Both this list and the one below are probably incorrectly categorised
            # as "operators" or "control flow". I'll leave their categorisation to somebody
            # familiar with JSONiq ⸻ @Alhadis
            name: "keyword.control.flow.$1.jsoniq"
            match: """(?x) \\b
                ( break
                | case
                | catch
                | continue
                | end
                | exit
                | for
                | from
                | if
                | import
                | in
                | loop
                | return
                | switch
                | then
                | try
                | when
                | where
                | while
                | with
                ) \\b
            """
        },{
            name: "keyword.operator.$1.jsoniq"
            match: """(?x) \\b
                ( after
                | allowing
                | ancestor-or-self
                | ancestor
                | and
                | append
                | array
                | ascending
                | as
                | attribute
                | at
                | base-uri
                | before
                | boundary-space
                | by
                | castable
                | cast
                | child
                | collation
                | comment
                | constraint
                | construction
                | contains
                | context
                | copy-namespaces
                | copy
                | count
                | decimal-format
                | decimal-separator
                | declare
                | default
                | delete
                | descendant-or-self
                | descendant
                | descending
                | digit
                | div
                | document-node
                | document
                | element
                | else
                | empty-sequence
                | empty
                | encoding
                | eq
                | every
                | except
                | external
                | first
                | following-sibling
                | following
                | ft-option
                | ge
                | greatest
                | grouping-separator
                | group
                | gt
                | idiv
                | index
                | infinity
                | insert
                | instance
                | integrity
                | intersect
                | into
                | is
                | item
                | json-item
                | jsoniq
                | json
                | last
                | lax
                | least
                | le
                | lt
                | minus-sign
                | modify
                | module
                | mod
                | namespace-node
                | namespace
                | next
                | ne
                | nodes
                | node
                | not
                | object
                | of
                | only
                | option
                | ordered
                | ordering
                | order
                | or
                | paragraphs
                | parent
                | pattern-separator
                | per-mille
                | percent
                | preceding-sibling
                | preceding
                | previous
                | processing-instruction
                | rename
                | replace
                | returning
                | revalidation
                | satisfies
                | schema-attribute
                | schema-element
                | schema
                | score
                | select
                | self
                | sentences
                | sliding
                | some
                | stable
                | start
                | strict
                | text
                | times
                | to
                | treat
                | tumbling
                | typeswitch
                | type
                | union
                | unordered
                | updating
                | validate
                | value
                | variable
                | version
                | window
                | words
                | xquery
                | zero-digit
                ) (?!:|-)\\b
            """
        }]

    EnclosedExpr:
        name: "meta.enclosed.expression.jsoniq"
        begin: "{"
        end:   "}"
        beginCaptures: 0: name: "punctuation.section.scope.begin.jsoniq"
        endCaptures:   0: name: "punctuation.section.scope.end.jsoniq"
        patterns: [include: "#main"]

    Numbers:
        patterns: [{
            name: "constant.numeric.exponential.jsoniq"
            match: "(?:\\.[0-9]+|\\b[0-9]+(?:\\.[0-9]*)?)[Ee][+#x002D]?[0-9]+\\b"
        },{
            name: "constant.numeric.float.jsoniq"
            match: "(?:\\.[0-9]+|\\b[0-9]+\\.[0-9]*)\\b"
        },{
            name: "constant.numeric.integer.jsoniq"
            match: "\\b[0-9]+\\b"
        }]

    OpenTag:
        name:  "meta.tag.opentag.jsoniq"
        begin: "(<)((?:[-_a-zA-Z0-9][-._a-zA-Z0-9]*:)?[-_a-zA-Z0-9][-_a-zA-Z0-9]*)"
        end:   "/?>"
        beginCaptures:
            1: name: "punctuation.definition.tag.begin.jsoniq"
            2: name: "entity.name.tag.localname.jsoniq"
        endCaptures:
            0: name: "punctuation.definition.tag.end.jsoniq"
        patterns: [{
            name: "entity.other.attribute-name.jsoniq"
            match: "([-_a-zA-Z0-9][-._a-zA-Z0-9]*:)?([-_a-zA-Z0-9][-_a-zA-Z0-9]*)"
        },{
            name: "keyword.operator.assignment.jsoniq"
            match: "="
        },{
            name:  "string.quoted.single.jsoniq"
            begin: "'"
            end:   "'(?!')"
            patterns: [
                {match: "''", name: "constant.character.escape.quote.jsoniq"}
                {include: "#PredefinedEntityRef"}
                {include: "#CharRef"}
                {match: "({{|}})", name:  "constant.jsoniq"}
                {include: "#EnclosedExpr"}
            ]
        },{
            name:  "string.quoted.double.jsoniq"
            begin: '"'
            end:   '"(?!")'
            patterns: [
                {match: '""', name: "constant.character.escape.quote.jsoniq"}
                {include: "#PredefinedEntityRef"}
                {include: "#CharRef"}
                {match: "({{|}})", name: "string.jsoniq"}
                {include: "#EnclosedExpr"}
            ]
        }]

    # (# … #)
    Pragma:
        name: "meta.pragma.jsoniq"
        begin: "\\(#"
        end:   "#\\)"
        beginCaptures: 0: name: "punctuation.definition.pragma.begin.jsoniq"
        endCaptures:   0: name: "punctuation.definition.pragma.end.jsoniq"
        contentName: "constant.other.pragma.jsoniq"

    PredefinedEntityRef:
        name: "constant.language.entity.predefined.jsoniq"
        match: "(&)(lt|gt|amp|quot|apos)(;)"
        captures:
            1: name: "punctuation.definition.entity.begin.jsoniq"
            2: name: "entity.name.entity.other.jsoniq"
            3: name: "punctuation.definition.entity.end.jsoniq"    

    # "Double-quoted string"
    String:
        name:  "string.quoted.double.jsoniq"
        begin: '"'
        end:   '"'
        patterns: [{
            name: "constant.character.escape.jsoniq"
            match: '\\\\(?:["\\\\/bfnrt]|u[0-9a-fA-F]{4})'
        },{
            name: "invalid.illegal.unrecognized-string-escape.jsoniq"
            match: "\\\\."
        }]

    # Punctuation and stuff
    Symbols:
        patterns: [
            {match: ":=?", name: "keyword.operator.assignment.definition.jsoniq"}
            {match: ",",   name: "punctuation.separator.delimiter.comma.jsoniq"}
            {match: "\\.", name: "punctuation.separator.delimiter.dot.jsoniq"}
            {match: "\\[", name: "punctuation.definition.bracket.square.begin.jsoniq"}
            {match: "\\]", name: "punctuation.definition.bracket.square.end.jsoniq"}
            {match: "\\{", name: "punctuation.definition.bracket.curly.begin.jsoniq"}
            {match: "\\}", name: "punctuation.definition.bracket.curly.end.jsoniq"}
            {match: "\\(", name: "punctuation.definition.bracket.round.begin.jsoniq"}
            {match: "\\)", name: "punctuation.definition.bracket.round.end.jsoniq"}
        ]

    # $variable_name
    Variable:
        name: "meta.definition.variable.name.jsoniq"
        match: "(\\$)(?:[-_a-zA-Z0-9][-._a-zA-Z0-9]*:)?[-_a-zA-Z0-9][-_a-zA-Z0-9]*"
        captures:
            0: name: "variable.other.jsoniq"
            1: name: "punctuation.definition.variable.jsoniq"

    #  <!-- … -->
    XMLComment:
        name: "comment.block.jsoniq"
        begin: "<!--"
        end:   "-->"
        beginCaptures: 0: name: "punctuation.definition.comment.begin.jsoniq"
        endCaptures:   0: name: "punctuation.definition.comment.end.jsoniq"