$schema: 'https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json'
name: ZoKrates
fileTypes:
    - zok
scopeName: source.zok
patterns:
    -
        comment: attributes
        name: meta.attribute.zokrates
        begin: '(#)(\!?)(\[)'
        beginCaptures:
            '1':
                name: punctuation.definition.attribute.zokrates
            '2':
                name: keyword.operator.attribute.inner.zokrates
            '3':
                name: punctuation.brackets.attribute.zokrates
        end: '\]'
        endCaptures:
            '0':
                name: punctuation.brackets.attribute.zokrates
        patterns:
            -
                include: '#block-comments'
            -
                include: '#comments'
            -
                include: '#keywords'
            -
                include: '#punctuation'
            -
                include: '#strings'
            -
                include: '#types'
    -
        include: '#block-comments'
    -
        include: '#comments'
    -
        include: '#constants'
    -
        include: '#functions'
    -
        include: '#types'
    -
        include: '#keywords'
    -
        include: '#punctuation'
    -
        include: '#strings'
    -
        include: '#variables'
repository:
    comments:
        patterns:
            -
                comment: 'line comments'
                name: comment.line.double-slash.zokrates
                match: '\s*//.*'
    block-comments:
        patterns:
            -
                comment: 'empty block comments'
                name: comment.block.zokrates
                match: '/\*\*/'
            -
                comment: 'block comments'
                name: comment.block.zokrates
                begin: '/\*(?!\*)'
                end: '\*/'
                patterns:
                    - {include: '#block-comments'}
    constants:
        patterns:
            -
                comment: 'ALL CAPS constants'
                name: constant.other.caps.zokrates
                match: '\b[A-Z]{2}[A-Z0-9_]*\b'
            -
                comment: 'decimal integers and floats'
                name: constant.numeric.decimal.zokrates
                match: '\b\d[\d_]*(?:u16|u32|u64|u8|f)?\b'
            -
                comment: 'hexadecimal integers'
                name: constant.numeric.hex.zokrates
                match: '\b0x[\da-fA-F_]+\b'
            -
                comment: booleans
                name: constant.language.bool.zokrates
                match: \b(true|false)\b
    imports:
        patterns:
            -
                comment: 'explicit import statement'
                name: meta.import.explicit.zokrates
                match: '\b(from)\s+(\".*\")(import)\s+([A-Za-z0-9_]+)\s+((as)\s+[A-Za-z0-9_]+)?\b'
                patterns:
                    - {include: '#block-comments'}
                    - {include: '#comments'}
                    - {include: '#keywords'}
                    - {include: '#punctuation'}
                    - {include: '#types'}
                    - {include: '#strings'}
            -
                comment: 'main import statement'
                name: meta.import.explicit.zokrates
                match: '\b(import)\s+(\".*\")\s+((as)\s+[A-Za-z0-9_]+)?\b'
                patterns:
                    - {include: '#block-comments'}
                    - {include: '#comments'}
                    - {include: '#keywords'}
                    - {include: '#punctuation'}
                    - {include: '#types'}
                    - {include: '#strings'}
    constant-definitions:
        patterns:
            -
                comment: 'constant definition'
                name: meta.constant.definition.zokrates
                match: '\b(const)\s+([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)\s+=\s+(?:.+)\b'
                captures:
                    '1': {name: keyword.other.const.zokrates}
                    '2': {name: entity.name.type.zokrates}
                    '3': {name: entity.name.constant.zokrates}
                patterns:
                    - {include: '#block-comments'}
                    - {include: '#comments'}
                    - {include: '#keywords'}
                    - {include: '#constants'}
                    - {include: '#punctuation'}
                    - {include: '#types'}
                    - {include: '#variables'}
    functions:
        patterns:
            -
                comment: 'function definition'
                name: meta.function.definition.zokrates
                begin: '\b(def)\s+([A-Za-z0-9_]+)((\()|(<))'
                beginCaptures:
                    '1': {name: keyword.other.def.zokrates}
                    '2': {name: entity.name.function.zokrates}
                    '4': {name: punctuation.brackets.round.zokrates}
                    '5': {name: punctuation.brackets.angle.zokrates}
                end: '\:|;'
                endCaptures:
                    '0': {name: keyword.punctuation.colon.zokrates}
                patterns:
                    - {include: '#block-comments'}
                    - {include: '#comments'}
                    - {include: '#keywords'}
                    - {include: '#constants'}
                    - {include: '#functions'}
                    - {include: '#punctuation'}
                    - {include: '#strings'}
                    - {include: '#types'}
                    - {include: '#variables'}
            -
                comment: 'function/method calls, chaining'
                name: meta.function.call.zokrates
                begin: '([A-Za-z0-9_]+)(\()'
                beginCaptures:
                    '1': {name: entity.name.function.zokrates}
                    '2': {name: punctuation.brackets.round.zokrates}
                end: \)
                endCaptures:
                    '0': {name: punctuation.brackets.round.zokrates}
                patterns:
                    - {include: '#block-comments'}
                    - {include: '#comments'}
                    - {include: '#keywords'}
                    - {include: '#constants'}
                    - {include: '#functions'}
                    - {include: '#punctuation'}
                    - {include: '#strings'}
                    - {include: '#types'}
                    - {include: '#variables'}
            -
                comment: 'function/method calls with turbofish'
                name: meta.function.call.zokrates
                begin: '([A-Za-z0-9_]+)(?=::<.*>\()'
                beginCaptures:
                    '1': {name: entity.name.function.zokrates}
                end: \)
                endCaptures:
                    '0': {name: punctuation.brackets.round.zokrates}
                patterns:
                    - {include: '#block-comments'}
                    - {include: '#comments'}
                    - {include: '#keywords'}
                    - {include: '#constants'}
                    - {include: '#functions'}
                    - {include: '#punctuation'}
                    - {include: '#strings'}
                    - {include: '#types'}
                    - {include: '#variables'}
    keywords:
        patterns:
            -
                comment: 'argument visibility'
                name: keyword.visibility.zokrates
                match: \b(public|private)\b
            -
                comment: 'control flow keywords'
                name: keyword.control.zokrates
                match: \b(for|in|if|else|return|assert|log)\b
            -
                comment: 'storage keywords'
                name: storage.type.zokrates
                match: \b(struct)\b
            -
                comment: 'const keyword'
                name: keyword.other.const.zokrates
                match: \b(const)\b
            -
                comment: 'type keyword'
                name: keyword.other.type.zokrates
                match: \b(type)\b
            -
                comment: 'def keyword'
                name: keyword.other.def.zokrates
                match: \b(def)\b
            -
                comment: 'import keywords'
                name: keyword.other.import.zokrates
                match: \b(import|from|as)\b
            -
                comment: 'logical operators'
                name: keyword.operator.logical.zokrates
                match: '(\^|\||\|\||&|&&|<<|>>|!)(?!=)'
            -
                comment: 'mut'
                name: "storage.modifier.mut.zokrates"
                match: \b(mut)\b
            -
                comment: 'single equal'
                name: keyword.operator.assignment.equal.zokrates
                match: '(?<![<>])=(?!=|>)'
            -
                comment: 'comparison operators'
                name: keyword.operator.comparison.zokrates
                match: '(=(=)?(?!>)|!=|<=|(?<!=)>=)'
            -
                comment: 'math operators'
                name: keyword.operator.math.zokrates
                match: '(([+%]|(\*(?!\w)))(?!=))|(-(?!>))|(/(?!/))'
            -
                comment: 'less than, greater than (special case)'
                match: '(?:\b|(?:(\))|(\])|(\})))[ \t]+([<>])[ \t]+(?:\b|(?:(\()|(\[)|(\{)))'
                captures:
                    '1': {name: punctuation.brackets.round.zokrates}
                    '2': {name: punctuation.brackets.square.zokrates}
                    '3': {name: punctuation.brackets.curly.zokrates}
                    '4': {name: keyword.operator.comparison.zokrates}
                    '5': {name: punctuation.brackets.round.zokrates}
                    '6': {name: punctuation.brackets.square.zokrates}
                    '7': {name: punctuation.brackets.curly.zokrates}
            -
                comment: 'dot access'
                name: keyword.operator.access.dot.zokrates
                match: '\.(?!\.)'
            -
                comment: 'ranges, range patterns'
                name: keyword.operator.range.zokrates
                match: '\.{2}(=|\.)?'
            -
                comment: colon
                name: keyword.operator.colon.zokrates
                match: ':(?!:)'
            -
                comment: 'dashrocket, skinny arrow'
                name: keyword.operator.arrow.skinny.zokrates
                match: '->'
    types:
        patterns:
            -
                comment: 'numeric types'
                match: '(?<![A-Za-z])(u16|u32|u64|u8|field)\b'
                captures:
                    '1': {name: entity.name.type.numeric.zokrates}
            -
                comment: 'parameterized types'
                begin: '\b([A-Z][A-Za-z0-9]*)(<)'
                beginCaptures:
                    '1': {name: entity.name.type.zokrates}
                    '2': {name: punctuation.brackets.angle.zokrates}
                end: '>'
                endCaptures:
                    '0': {name: punctuation.brackets.angle.zokrates}
                patterns:
                    - {include: '#block-comments'}
                    - {include: '#comments'}
                    - {include: '#keywords'}
                    - {include: '#punctuation'}
                    - {include: '#types'}
                    - {include: '#variables'}
            -
                comment: 'primitive types'
                name: entity.name.type.primitive.zokrates
                match: \b(bool)\b
            -
                comment: 'struct declarations'
                match: '\b(struct)\s+([A-Z][A-Za-z0-9]*)\b'
                captures:
                    '1': {name: storage.type.zokrates}
                    '2': {name: entity.name.type.struct.zokrates}
            -
                comment: types
                name: entity.name.type.zokrates
                match: '\b[A-Z][A-Za-z0-9]*\b(?!!)'
    punctuation:
        patterns:
            -
                comment: comma
                name: punctuation.comma.zokrates
                match: ','
            -
                comment: 'curly braces'
                name: punctuation.brackets.curly.zokrates
                match: '[{}]'
            -
                comment: 'parentheses, round brackets'
                name: punctuation.brackets.round.zokrates
                match: '[()]'
            -
                comment: 'semicolon'
                name: punctuation.semi.zokrates
                match: ';'
            -
                comment: 'square brackets'
                name: punctuation.brackets.square.zokrates
                match: '[\[\]]'
            -
                comment: 'angle brackets'
                name: punctuation.brackets.angle.zokrates
                match: '(?<!=)[<>]'
    strings:
        patterns:
            -
                comment: 'double-quoted strings and byte strings'
                name: string.quoted.double.zokrates
                begin: '(b?)(")'
                beginCaptures:
                    '1': {name: string.quoted.byte.raw.zokrates}
                    '2': {name: punctuation.definition.string.zokrates}
                end: '"'
                endCaptures:
                    '0': {name: punctuation.definition.string.zokrates}
            -
                comment: 'double-quoted raw strings and raw byte strings'
                name: string.quoted.double.zokrates
                begin: '(b?r)(#*)(")'
                beginCaptures:
                    '1': {name: string.quoted.byte.raw.zokrates}
                    '2': {name: punctuation.definition.string.raw.zokrates}
                    '3': {name: punctuation.definition.string.zokrates}
                end: '(")(\2)'
                endCaptures:
                    '1': {name: punctuation.definition.string.zokrates}
                    '2': {name: punctuation.definition.string.raw.zokrates}
    variables:
        patterns:
            -
                comment: variables
                name: variable.other.zokrates
                match: '\b(?<!(?<!\.)\.)[a-z0-9_]+\b'
