text: %YAML 1.2
  ---
  # http://www.sublimetext.com/docs/3/syntax.html
  
  name: Clojure
  file_extensions:
    - clj
    - cljc
    - edn
  scope: source.clojure
  
  variables:
    non_symbol_chars: \s,;\(\)\[\]{}\"`~@\^\\
    non_symbol_start_chars: '{{non_symbol_chars}}\d#'':'
    non_number_chars: '{{non_symbol_chars}}#'''
    non_char_chars: '{{non_symbol_chars}}#'''
    atom: '[^{{non_symbol_chars}}]+'
    symbol: (?:/|[^{{non_symbol_start_chars}}][^{{non_symbol_chars}}]*)
    # Slightly too permissive
    keyword: (:):?[^:{{non_symbol_chars}}][^{{non_symbol_chars}}]*
    constant: (?:nil|true|false)(?=[{{non_symbol_chars}}])
    evil_octal: '[-+]?0\d+N?(?=[{{non_symbol_chars}}])'
  
    # Similar to the number regexps in the Clojure reader.
    # This doesn't include evil octals and dot-terminated decimals.
    sign: '[-+]?'
    exponent: (?:[eE]{{sign}}\d+)
    dec_integer: ({{sign}})(\d+)(N?)(?=[{{non_number_chars}}])
    hex_integer: ({{sign}})(0[Xx])(\h+)(N?)(?=[{{non_number_chars}}])
    other_integer: ({{sign}})((?:[2-9]|[1-9]\d+)[Rr])([0-9A-Za-z]+)(?=[{{non_number_chars}}])
    rational: ({{sign}})(\d+)(/)(\d+)(?=[{{non_number_chars}}])
    float: ({{sign}})(\d+)(?:(?:(\.)(\d+)({{exponent}})?|({{exponent}}))(M)?|(M))(?=[{{non_number_chars}}])
  
  contexts:
    main:
      - include: match-expr
  
    match-expr:
      - include: match-noise
      - match: '[)\]}]'
        scope: invalid.illegal.clojure
      - match: \(
        scope: punctuation.section.parens.begin.clojure
        push: pop-list-head
      - match: \[
        scope: punctuation.section.brackets.begin.clojure
        push:
          - match: \]
            scope: punctuation.section.brackets.end.clojure
            pop: true
          - include: match-expr
      - match: '#?{'
        scope: punctuation.section.braces.begin.clojure
        push:
          - match: '}'
            scope: punctuation.section.braces.end.clojure
            pop: true
          - include: match-expr
      - match: '"'
        scope: punctuation.definition.string.begin.clojure
        push: pop-string-tail
      - match: '#'
        scope: keyword.operator.macro.clojure
        push: pop-dispatch-expr
      - match: '''|`|~|@'
        scope: keyword.operator.macro.clojure
        push: pop-expr
      - match: \\\S[^{{non_char_chars}}]*
        scope: constant.character.clojure
      - match: '{{constant}}'
        scope: constant.language.clojure
      - match: '{{keyword}}'
        scope: constant.other.keyword.clojure
        captures:
          1: punctuation.definition.keyword.clojure
      - match: '{{evil_octal}}'
        scope: invalid.deprecated.clojure
      - match: '{{dec_integer}}'
        scope: meta.number.integer.decimal.clojure
        captures:
          1: punctuation.definition.numeric.sign.clojure
          2: constant.numeric.value.clojure
          3: constant.numeric.suffix.clojure
      - match: '{{hex_integer}}'
        scope: meta.number.integer.hexadecimal.clojure
        captures:
          1: punctuation.definition.numeric.sign.clojure
          2: constant.numeric.base.clojure
          3: constant.numeric.value.clojure
          4: constant.numeric.suffix.clojure
      - match: '{{other_integer}}'
        scope: meta.number.integer.other.clojure
        captures:
          1: punctuation.definition.numeric.sign.clojure
          2: constant.numeric.base.clojure
          3: constant.numeric.value.clojure
      - match: '{{rational}}'
        scope: meta.number.rational.decimal.clojure
        captures:
          1: punctuation.definition.numeric.sign.clojure
          2: constant.numeric.value.clojure
          3: punctuation.separator.rational.clojure
          4: constant.numeric.value.clojure
      - match: '{{float}}'
        scope: meta.number.float.decimal.clojure
        captures:
          1: punctuation.definition.numeric.sign.clojure
          2: constant.numeric.value.clojure
          3: punctuation.separator.decimal.clojure
          4: constant.numeric.value.clojure
          5: constant.numeric.value.exponent.clojure
          6: constant.numeric.value.exponent.clojure
          7: constant.numeric.suffix.clojure
          8: constant.numeric.suffix.clojure
      - match: '{{atom}}'
  
    pop-expr:
      - include: match-noise
      - match: '[)\]}]'
        scope: invalid.illegal.clojure
        pop: true
      - match: \(
        scope: punctuation.section.parens.begin.clojure
        set: pop-list-head
      - match: \[
        scope: punctuation.section.brackets.begin.clojure
        set:
          - match: \]
            scope: punctuation.section.brackets.end.clojure
            pop: true
          - include: match-expr
      - match: '#?{'
        scope: punctuation.section.braces.begin.clojure
        set:
          - match: '}'
            scope: punctuation.section.braces.end.clojure
            pop: true
          - include: match-expr
      - match: '"'
        scope: punctuation.definition.string.begin.clojure
        set: pop-string-tail
      - match: '#'
        scope: keyword.operator.macro.clojure
        set: pop-dispatch-expr
      - match: '''|`|~|@'
        scope: keyword.operator.macro.clojure
        set: pop-expr
      - match: '\\\S[^{{non_char_chars}}]*'
        scope: constant.character.clojure
        pop: true
      - match: '{{constant}}'
        scope: constant.language.clojure
        pop: true
      - match: '{{keyword}}'
        scope: constant.other.keyword.clojure
        captures:
          1: punctuation.definition.keyword.clojure
        pop: true
      - match: '{{evil_octal}}'
        scope: invalid.deprecated.clojure
        pop: true
      - match: '{{dec_integer}}'
        scope: meta.number.integer.decimal.clojure
        captures:
          1: punctuation.definition.numeric.sign.clojure
          2: constant.numeric.value.clojure
          3: constant.numeric.suffix.clojure
        pop: true
      - match: '{{hex_integer}}'
        scope: meta.number.integer.hexadecimal.clojure
        captures:
          1: punctuation.definition.numeric.sign.clojure
          2: constant.numeric.base.clojure
          3: constant.numeric.value.clojure
          4: constant.numeric.suffix.clojure
        pop: true
      - match: '{{other_integer}}'
        scope: meta.number.integer.other.clojure
        captures:
          1: punctuation.definition.numeric.sign.clojure
          2: constant.numeric.base.clojure
          3: constant.numeric.value.clojure
        pop: true
      - match: '{{rational}}'
        scope: meta.number.rational.decimal.clojure
        captures:
          1: punctuation.definition.numeric.sign.clojure
          2: constant.numeric.value.clojure
          3: punctuation.separator.rational.clojure
          4: constant.numeric.value.clojure
        pop: true
      - match: '{{float}}'
        scope: meta.number.float.decimal.clojure
        captures:
          1: punctuation.definition.numeric.sign.clojure
          2: constant.numeric.value.clojure
          3: punctuation.separator.decimal.clojure
          4: constant.numeric.value.clojure
          5: constant.numeric.value.exponent.clojure
          6: constant.numeric.value.exponent.clojure
          7: constant.numeric.suffix.clojure
          8: constant.numeric.suffix.clojure
        pop: true
      - match: '{{atom}}'
        pop: true
  
    match-noise:
      # Explicitly matching \s also captures end-of-line; this allows apostrophe
      # pairing to work at the last cursor position in a comment line.
      - match: (;+|#!)(.|\s)*
        scope: comment.line.clojure
        captures:
          1: punctuation.definition.comment
      - match: ','
        scope: punctuation.comma.clojure comment.punctuation.comma.clojure
      - match: \^
        scope: keyword.operator.macro.clojure
        push: pop-expr
  
    pop-dispatch-expr:
      - match: (?=\s)
        set: pop-dispatch-tag-expr
      - match: _
        scope: keyword.operator.macro.clojure
        set: pop-expr
      - match: '#'
        scope: keyword.operator.macro.clojure
        set: pop-symbolic-value
      - match: "'"
        scope: keyword.operator.macro.clojure
        pop: true
      - match: '"'
        scope: punctuation.definition.string.begin.clojure
        set: pop-regexp-tail
      - match: (?=[\^:])
        pop: true
      - match: (?=\S)
        set: pop-dispatch-tag-expr
  
    pop-dispatch-tag-expr:
      - include: match-noise
      - match: '{{symbol}}'
        scope: keyword.operator.macro.clojure
        pop: true
      - match: (?=\S)
        set: pop-expr
  
    pop-symbolic-value:
      - include: match-noise
      - match: '{{atom}}'
        scope: constant.other.symbolic.clojure
        pop: true
      - match: (?=\S)
        set: pop-expr
  
    pop-regexp-tail:
      - meta_scope: string.regexp.clojure
      - match: '"'
        scope: punctuation.definition.string.end.clojure
        pop: true
      - match: ''
        push: scope:source.regexp#base-literal
        with_prototype:
          - match: (?=")
            pop: true
  
    pop-string-tail:
      - meta_scope: string.quoted.double.clojure
      - match: \\.
        scope: constant.character.escape.clojure
      - match: '"'
        scope: punctuation.definition.string.end.clojure
        pop: true
  
    pop-list-head:
      - include: match-noise
      - match: defprotocol[^{{non_symbol_chars}}]*
        scope: storage.type.clojure
        set: pop-declare-protocol-list-tail
      - match: definterface[^{{non_symbol_chars}}]*
        scope: storage.type.clojure
        set: pop-declare-interface-list-tail
      - match: (?:deftype|defrecord)[^{{non_symbol_chars}}]*
        scope: storage.type.clojure
        set: pop-declare-type-list-tail
      - match: defmethod[^{{non_symbol_chars}}]*
        scope: storage.modifier.def.clojure
        set: pop-fn-list-tail
      - match: def[^{{non_symbol_chars}}]*
        scope: storage.modifier.def.clojure
        set: pop-declare-def-list-tail
      - match: (?:reify|proxy|extend-protocol|extend-type)[^{{non_symbol_chars}}]*
        scope: variable.function.clojure
        set: pop-type-list-tail
      - match: fn\*?(?=[{{non_symbol_chars}}])
        scope: storage.modifier.fn.clojure
        set: pop-fn-list-tail
      - match: declare[^{{non_symbol_chars}}]*
        scope: storage.modifier.declare.clojure
        set: pop-declare-list-tail
      - match: (?=\S)
        set: pop-invoke-list-tail
  
    pop-list-tail:
      - match: \)
        scope: punctuation.section.parens.end.clojure
        pop: true
      - include: match-expr
  
    pop-declare-protocol-list-tail:
      - include: match-constant-set-normal-list-tail
      - match: '{{symbol}}'
        scope: entity.name.type.clojure
        set: pop-protocol-list-tail
      - include: set-normal-list-tail
  
    pop-protocol-list-tail:
      - match: \)
        scope: punctuation.section.parens.end.clojure
        pop: true
      - match: \(
        scope: punctuation.section.parens.begin.clojure
        push: pop-declare-def-list-tail
      - include: match-expr
  
    pop-declare-interface-list-tail:
      - include: match-constant-set-normal-list-tail
      - match: '{{symbol}}'
        scope: entity.name.type.clojure
        set: pop-interface-list-tail
      - include: set-normal-list-tail
  
    pop-interface-list-tail:
      - match: \)
        scope: punctuation.section.parens.end.clojure
        pop: true
      - match: \(
        scope: punctuation.section.parens.begin.clojure
        push: pop-fn-list-tail
      - include: match-expr
  
    pop-declare-type-list-tail:
      - include: match-constant-set-normal-list-tail
      - match: '{{symbol}}'
        scope: entity.name.type.clojure
        set: pop-type-list-tail
      - include: set-normal-list-tail
  
    pop-type-list-tail:
      - match: \)
        scope: punctuation.section.parens.end.clojure
        pop: true
      - match: \(
        scope: punctuation.section.parens.begin.clojure
        push: pop-fn-list-tail
      - include: match-symbol-implemented-or-extended
      - include: match-expr
  
    pop-declare-def-list-tail:
      - include: match-constant-set-normal-list-tail
      - match: '{{symbol}}'
        scope: entity.name.function.clojure
        set: pop-list-tail
      - include: set-normal-list-tail
  
    pop-fn-list-tail:
      - include: match-constant-set-normal-list-tail
      - match: '{{symbol}}'
        scope: entity.name.function.fn.clojure
        set: pop-list-tail
      - include: set-normal-list-tail
  
    pop-declare-list-tail:
      - include: match-constant-set-normal-list-tail
      - match: '{{symbol}}'
        scope: entity.name.function.forward-decl.clojure
        set: pop-list-tail
      - include: set-normal-list-tail
  
    pop-invoke-list-tail:
      - include: match-constant-set-normal-list-tail
      - match: '{{symbol}}'
        scope: variable.function.clojure
        set: pop-list-tail
      - include: set-normal-list-tail
  
    match-constant-set-normal-list-tail:
      - include: match-noise
      - match: '{{constant}}'
        scope: constant.language.clojure
        set: pop-list-tail
  
    match-symbol-implemented-or-extended:
      - match: '{{constant}}'
        scope: constant.language.clojure
      - match: '{{symbol}}'
        scope: entity.other.inherited-class.clojure
  
    set-normal-list-tail:
      - match: (?=\S)
        set: pop-list-tail
  