%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: "F#"
file_extensions:
  - fs
  - fsi
  - fsx
scope: source.fsharp
contexts:
  main:
    - include: compiler_directives
    - include: comments
    - include: constants
    - include: strings
    - include: chars
    - include: double_tick
    - include: definition
    - include: abstract_definition
    - include: attributes
    - include: modules
    - include: anonymous_functions
    - include: du_declaration
    - include: record_declaration
    - include: records
    - include: strp_inlined
    - include: keywords
    - include: cexprs
    - include: text
  abstract_definition:
    - match: '\b(abstract)\s+(member)?(\s+\[\<.*\>\])?\s*([_[:alpha:]0-9,\._`\s]+)(:)'
      captures:
        1: keyword.fsharp
        2: keyword.fsharp
        3: support.function.attribute.fsharp
        5: keyword.fsharp
      push:
        - meta_scope: abstract.definition.fsharp
        - match: \s*(with)\b|=|$
          captures:
            1: keyword.fsharp
          pop: true
        - include: comments
        - include: common_declaration
        - match: '(\?{0,1})([[:alpha:]0-9''`^._ ]+)\s*(:)(\s*([[:alpha:]0-9''`^._ ]+)){0,1}'
          captures:
            1: keyword.symbol.fsharp
            2: variable.parameter.fsharp
            3: keyword.symbol.fsharp
            4: entity.name.type.fsharp
        - match: '(?!with|get|set\b)\b([\w0-9''`^._]+)'
          captures:
            1: entity.name.type.fsharp
        - include: keywords
  anonymous_functions:
    - match: \b(fun)\b
      captures:
        1: keyword.fsharp
      push:
        - meta_scope: function.anonymous
        - match: (->)
          captures:
            1: keyword.fsharp
          pop: true
        - include: comments
        - match: (\()
          captures:
            1: keyword.symbol.fsharp
          push:
            - match: \s*(?=(->))
              captures:
                1: keyword.symbol.fsharp
              pop: true
            - include: member_declaration
        - include: variables
  attributes:
    - match: '\[\<'
      push:
        - meta_scope: support.function.attribute.fsharp
        - match: '\>\]|\]'
          pop: true
        - include: main
  cexprs:
    - match: '\b(async|seq|promise|task|maybe|asyncMaybe|controller|scope|application|pipeline)\s*\{'
      scope: cexpr.fsharp
      captures:
        0: keyword.fsharp
  chars:
    - match: ('\\?.')
      scope: char.fsharp
      captures:
        1: string.quoted.single.fsharp
  comments:
    - match: (\(\*(?!\)))
      captures:
        1: comment.block.fsharp
      push:
        - meta_scope: comment.block.fsharp
        - match: (\*\))
          captures:
            1: comment.block.fsharp
          pop: true
    - match: //.*$
      scope: comment.line.double-slash.fsharp
  common_binding_definition:
    - include: comments
    - include: attributes
    - match: (:)\s*(\()\s*(static member|member)
      captures:
        1: keyword.symbol.fsharp
        2: keyword.symbol.fsharp
        3: keyword.fsharp
      push:
        - match: (\))\s*((?=,)|(?=\=))
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - match: '(\^[[:alpha:]0-9''._]+)'
          captures:
            1: entity.name.type.fsharp
        - include: variables
        - include: keywords
    - match: (:)\s*(\()
      captures:
        1: keyword.symbol.fsharp
        2: keyword.symbol.fsharp
      push:
        - match: '(\)\s*(([?[:alpha:]0-9''`^._ ]*)))'
          captures:
            1: keyword.symbol.fsharp
            2: entity.name.type.fsharp
          pop: true
        - include: tuple_signature
    - match: '(:)\s*(\^[[:alpha:]0-9''._]+)\s*(when)'
      captures:
        1: keyword.symbol.fsharp
        2: entity.name.type.fsharp
        3: keyword.fsharp
      push:
        - match: (?=:)
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - match: \b(and|when|or)\b
          scope: keyword.fsharp
        - match: "([[:alpha:]0-9'^._]+)"
          comment: Because we first capture the keywords, we can capture what looks like a word and assume it's an entity definition
          captures:
            1: entity.name.type.fsharp
        - match: (\(|\))
          scope: keyword.symbol.fsharp
    - match: '(:)\s*([?[:alpha:]0-9''`^._ ]+)'
      captures:
        1: keyword.symbol.fsharp
        2: entity.name.type.fsharp
    - match: '(->)\s*(\()?\s*([?[:alpha:]0-9''`^._ ]+)*'
      captures:
        1: keyword.symbol.fsharp
        2: keyword.symbol.fsharp
        3: entity.name.type.fsharp
    - match: (\*)\s*(\()
      captures:
        1: keyword.symbol.fsharp
        2: keyword.symbol.fsharp
      push:
        - match: '(\)\s*(([?[:alpha:]0-9''`^._ ]+))+)'
          captures:
            1: keyword.symbol.fsharp
            2: entity.name.type.fsharp
          pop: true
        - include: tuple_signature
    - match: '(\*)(\s*([?[:alpha:]0-9''`^._ ]+))*'
      captures:
        1: keyword.symbol.fsharp
        2: entity.name.type.fsharp
    - match: '(<(?![[:space:]]*\)))'
      captures:
        1: keyword.symbol.fsharp
      push:
        - match: ((?<!:)>)
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - include: generic_declaration
    - match: "({)"
      captures:
        1: keyword.symbol.fsharp
      push:
        - match: "(})"
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - include: record_signature
    - include: definition
    - include: variables
    - include: keywords
  common_declaration:
    - match: '\s*(->)\s*([[:alpha:]0-9''`^._ ]+)(<)'
      captures:
        1: keyword.symbol.fsharp
        2: entity.name.type.fsharp
        3: keyword.symbol.fsharp
      push:
        - match: (>)
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - match: "([[:alpha:]0-9'`^._ ]+)"
          captures:
            1: entity.name.type.fsharp
        - include: keywords
    - match: '\s*(->)\s*(?!with|get|set\b)\b([\w0-9''`^._]+)'
      captures:
        1: keyword.symbol.fsharp
        2: entity.name.type.fsharp
    - match: '(\?{0,1})([[:alpha:]0-9''`^._ ]+)\s*(:)(\s*([?[:alpha:]0-9''`^._ ]+)(<))'
      captures:
        1: keyword.symbol.fsharp
        2: variable.parameter.fsharp
        3: keyword.symbol.fsharp
        4: keyword.symbol.fsharp
        5: entity.name.type.fsharp
      push:
        - match: (>)
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - match: "([[:alpha:]0-9'`^._ ]+)"
          captures:
            1: entity.name.type.fsharp
        - include: keywords
  compiler_directives:
    - match: \s?(#if|#elif|#else|#elseif|#endif|#light|#nowarn)
      scope: compiler_directive.fsharp
      captures:
  constants:
    - match: \(\)
      scope: constant.language.unit.fsharp
    - match: '\b-?[0-9][0-9_]*((\.([0-9][0-9_]*([eE][+-]??[0-9][0-9_]*)?)?)|([eE][+-]??[0-9][0-9_]*))'
      scope: constant.numeric.floating-point.fsharp
    - match: '\b(-?((0(x|X)[0-9a-fA-F][0-9a-fA-F_]*)|(0(o|O)[0-7][0-7_]*)|(0(b|B)[01][01_]*)|([0-9][0-9_]*)))'
      scope: constant.numeric.integer.nativeint.fsharp
    - match: \b(true|false|null|unit)\b
      scope: constant.others.fsharp
  definition:
    - match: '\b(let mutable|static let mutable|let inline|let|member val|static member inline|static member|default|member|override|let!)(\s+rec|mutable)?(\s+\[\<.*\>\])?\s*(private|internal|public)?\s+(\[[^-=]*\]|[_[:alpha:]]([_[:alpha:]0-9,\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9,\._`\s]+|(?<=,)\s)*)?'
      captures:
        1: keyword.fsharp
        2: keyword.fsharp
        3: support.function.attribute.fsharp
        4: keyword.fsharp
        5: variable.fsharp
      push:
        - meta_scope: binding.fsharp
        - match: \s*(with\b|=|\n+=|(?<=\=))
          captures:
            1: keyword.fsharp
          pop: true
        - include: common_binding_definition
    - match: '\b(static val mutable|val mutable|val)(\s+rec|mutable)?(\s+\[\<.*\>\])?\s*(private|internal|public)?\s+(\[[^-=]*\]|[_[:alpha:]]([_[:alpha:]0-9,\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9,\._`\s]+|(?<=,)\s)*)?'
      captures:
        1: keyword.fsharp
        2: keyword.fsharp
        3: support.function.attribute.fsharp
        4: keyword.fsharp
        5: variable.fsharp
      push:
        - meta_scope: binding.fsharp
        - match: \n$
          pop: true
        - include: common_binding_definition
  double_tick:
    - match: (``)(.*)(``)
      scope: variable.other.binding.fsharp
      captures:
        1: string.quoted.single.fsharp
        2: variable.other.binding.fsharp
        3: string.quoted.single.fsharp
  du_declaration:
    - match: \b(of)\b
      captures:
        1: keyword.fsharp
      push:
        - meta_scope: du_declaration.fsharp
        - match: $|(\|)
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - include: comments
        - match: '([[:alpha:]0-9''`<>^._]+|``[[:alpha:]0-9'' <>^._]+``)\s*(:)\s*([[:alpha:]0-9''`<>^._]+|``[[:alpha:]0-9'' <>^._]+``)'
          captures:
            1: variable.parameter.fsharp
            2: keyword.symbol.fsharp
            3: entity.name.type.fsharp
        - match: "([[:alpha:]0-9'`^._]+)|``([[:alpha:]0-9'^._ ]+)``"
          captures:
            1: entity.name.type.fsharp
        - include: keywords
  generic_declaration:
    - match: (:)\s*(\()\s*(static member|member)
      captures:
        1: keyword.symbol.fsharp
        2: keyword.symbol.fsharp
        3: keyword.fsharp
      push:
        - match: (\))
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - match: (\()
          captures:
            1: keyword.symbol.fsharp
          push:
            - match: (\))
              captures:
                1: keyword.symbol.fsharp
              pop: true
            - include: member_declaration
        - match: '((''|\^)[[:alpha:]0-9''._]+)'
          captures:
            1: entity.name.type.fsharp
        - include: variables
        - include: keywords
    - match: \b(private|to|public|internal|function|yield!|yield|class|exception|match|delegate|of|new|in|as|if|then|else|elif|for|begin|end|inherit|do|let\!|return\!|return|interface|with|abstract|property|union|enum|member|try|finally|and|when|use|use\!|struct|while|mutable)(?!')\b
      scope: keyword.fsharp
    - match: ":"
      scope: keyword.fsharp
    - include: constants
    - match: '((''|\^)[[:alpha:]0-9''._]+)'
      captures:
        1: entity.name.type.fsharp
    - match: (<)
      captures:
        1: keyword.symbol.fsharp
      push:
        - match: (>)
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - match: '((''|\^)[[:alpha:]0-9''._]+)'
          captures:
            1: entity.name.type.fsharp
        - include: tuple_signature
        - include: generic_declaration
    - match: '(?!when|and|or\b)\b([\w0-9''`^._]+)'
      captures:
        1: entity.name.type.fsharp
    - match: (\|)
      captures:
        1: keyword.symbol.fsharp
    - include: keywords
  keywords:
    - match: \b(private|to|public|internal|function|yield!|yield|class|exception|match|delegate|of|new|in|as|if|then|else|elif|for|begin|end|inherit|do|let\!|return\!|return|interface|with|abstract|property|union|enum|member|try|finally|and|when|or|use|use\!|struct|while|mutable)(?!')\b
      scope: keyword.fsharp
    - match: '(&&&|\|\|\||\^\^\^|~~~|<<<|>>>|\|>|\->|\<\-|:>|:\?>|:|\[|\]|\;|<>|=|@|\|\||&&|{|}|\||_|\.\.|\,|\+|\-|\*|\/|\^|\!|\>|\>\=|\>\>|\<|\<\=|\(|\)|\<\<)'
      scope: keyword.symbol.fsharp
  member_declaration:
    - include: comments
    - include: common_declaration
    - match: (:)\s*(\()\s*(static member|member)
      captures:
        1: keyword.symbol.fsharp
        2: keyword.symbol.fsharp
        3: keyword.fsharp
      push:
        - match: (\))\s*((?=,)|(?=\=))
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - match: (\()
          captures:
            1: keyword.symbol.fsharp
          push:
            - match: (\))
              captures:
                1: keyword.symbol.fsharp
              pop: true
            - include: member_declaration
        - match: '(\^[[:alpha:]0-9''._]+)'
          captures:
            1: entity.name.type.fsharp
        - include: variables
        - include: keywords
    - match: '(\^[[:alpha:]0-9''._]+)'
      captures:
        1: entity.name.type.fsharp
    - match: \b(and|when|or)\b
      scope: keyword.fsharp
    - match: (\(|\))
      scope: keyword.symbol.fsharp
    - match: '(\?{0,1})([[:alpha:]0-9''`^._]+|``[[:alpha:]0-9''`^:,._ ]+``)\s*(:{0,1})(\s*([?[:alpha:]0-9''`<>._ ]+)){0,1}'
      captures:
        1: keyword.symbol.fsharp
        2: variable.parameter.fsharp
        3: keyword.symbol.fsharp
        4: entity.name.type.fsharp
    - include: keywords
  modules:
    - match: '\b(namespace|module)\s*(public|internal|private)?\s+([[:alpha:]][[:alpha:]0-9''_. ]*)'
      captures:
        1: keyword.fsharp
        2: keyword.fsharp
        3: entity.name.section.fsharp
      push:
        - meta_scope: entity.name.section.fsharp
        - match: (\s?=|\s|$)
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - match: '(\.)([A-Z][[:alpha:]0-9''_]*)'
          scope: entity.name.section.fsharp
          captures:
            1: punctuation.separator.namespace-reference.fsharp
            2: entity.name.section.fsharp
    - match: '\b(open)\s+([[:alpha:]][[:alpha:]0-9''_]*)(?=(\.[A-Z][[:alpha:]0-9_]*)*)'
      captures:
        1: keyword.fsharp
        2: entity.name.section.fsharp
      push:
        - meta_scope: namespace.open.fsharp
        - match: (\s|$)
          pop: true
        - match: '(\.)([[:alpha:]][[:alpha:]0-9''_]*)'
          scope: entity.name.section.fsharp
          captures:
            1: punctuation.separator.namespace-reference.fsharp
            2: entity.name.section.fsharp
    - match: '^\s*(module)\s+([A-Z][[:alpha:]0-9''_]*)\s*(=)\s*([A-Z][[:alpha:]0-9''_]*)'
      captures:
        1: keyword.fsharp
        2: entity.name.type.namespace.fsharp
        3: punctuation.separator.namespace-definition.fsharp
        4: entity.name.section.fsharp
      push:
        - meta_scope: namespace.alias.fsharp
        - match: (\s|$)
          pop: true
        - match: '(\.)([A-Z][[:alpha:]0-9''_]*)'
          scope: entity.name.section.fsharp
          captures:
            1: punctuation.separator.namespace-reference.fsharp
            2: entity.name.section.fsharp
  record_declaration:
    - match: '(\{)'
      captures:
        1: keyword.symbol.fsharp
      push:
        - match: '(?<=\})'
          pop: true
        - include: comments
        - match: '(((mutable)\s[[:alpha:]]+)|[[:alpha:]0-9''`<>^._]*)\s*((?<!:):(?!:))\s*'
          captures:
            3: keyword.fsharp
            4: keyword.symbol.fsharp
          push:
            - match: '$|(;|\})'
              captures:
                1: keyword.symbol.fsharp
              pop: true
            - include: comments
            - match: "([[:alpha:]0-9'`^_ ]+)"
              captures:
                1: entity.name.type.fsharp
            - include: keywords
        - include: compiler_directives
        - include: constants
        - include: strings
        - include: chars
        - include: double_tick
        - include: definition
        - include: attributes
        - include: anonymous_functions
        - include: keywords
        - include: cexprs
        - include: text
  record_signature:
    - match: "[[:alpha:]0-9'`^_ ]+(=)([[:alpha:]0-9'`^_ ]+)"
      captures:
        1: keyword.symbol.fsharp
        2: variable.parameter.fsharp
    - match: "({)"
      captures:
        1: keyword.symbol.fsharp
      push:
        - match: "(})"
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - match: "[[:alpha:]0-9'`^_ ]+(=)([[:alpha:]0-9'`^_ ]+)"
          captures:
            1: keyword.symbol.fsharp
            2: variable.parameter.fsharp
        - include: record_signature
    - include: keywords
  records:
    - match: '\b(type)[\s]+(private|internal|public)?\s*'
      captures:
        1: keyword.fsharp
        2: keyword.fsharp
      push:
        - meta_scope: record.fsharp
        - match: '\s*((with)|((as)\s+([[:alpha:]0-9'']+))|(=)|[\n=]|(\(\)))'
          captures:
            2: keyword.fsharp
            3: keyword.fsharp
            4: keyword.fsharp
            5: variable.parameter.fsharp
            6: keyword.symbol.fsharp
            7: constant.language.unit.fsharp
          pop: true
        - include: comments
        - include: attributes
        - match: "([[:alpha:]0-9'^._]+|``[[:alpha:]0-9'`^:,._ ]+``)"
          captures:
            1: entity.name.type.fsharp
        - match: (<)
          captures:
            1: keyword.fsharp
          push:
            - match: ((?<!:)>)
              captures:
                1: keyword.fsharp
              pop: true
            - match: '((''|\^)``[[:alpha:]0-9`^:,._ ]+``|(''|\^)[[:alpha:]0-9`^:._]+)'
              captures:
                1: entity.name.type.fsharp
            - match: \b(interface|with|abstract|and|when|or|not|struct|equality|comparison|unmanaged|delegate|enum)\b
              scope: keyword.fsharp
            - match: (\()
              captures:
                1: keyword.symbol.fsharp
              push:
                - match: (\))
                  captures:
                    1: keyword.symbol.fsharp
                  pop: true
                - match: (static member|member|new)
                  captures:
                    1: keyword.fsharp
                - include: common_binding_definition
            - match: '([\w0-9''`^._]+)'
              captures:
                1: entity.name.type.fsharp
            - include: keywords
        - match: \s*(private|internal|public)
          captures:
            1: keyword.symbol.fsharp
            2: keyword.fsharp
        - match: (\()
          captures:
            1: keyword.symbol.fsharp
          push:
            - match: '\s*(?=(=)|[\n=]|(\(\))|(as))'
              captures:
                1: keyword.symbol.fsharp
              pop: true
            - include: member_declaration
        - include: keywords
  string_formatter:
    - match: (%0?-?(\d+)?((a|t)|(\.\d+)?(f|F|e|E|g|G|M)|(b|c|s|d|i|x|X|o|u)|(s|b|O)|(\+?A)))
      scope: entity.name.type.format.specifier.fsharp
      captures:
        1: keyword.format.specifier.fsharp
  strings:
    - match: '(?=[^\\])(@")'
      captures:
        1: punctuation.definition.string.begin.fsharp
      push:
        - meta_scope: string.quoted.literal.fsharp
        - match: (")(?!")
          captures:
            1: punctuation.definition.string.end.fsharp
          pop: true
        - match: '"(")'
          scope: constant.character.string.escape.fsharp
    - match: '(?=[^\\])(""")'
      captures:
        1: punctuation.definition.string.begin.fsharp
      push:
        - meta_scope: string.quoted.triple.fsharp
        - match: (""")
          captures:
            1: punctuation.definition.string.end.fsharp
          pop: true
        - include: string_formatter
    - match: '(?=[^\\])(")'
      captures:
        1: punctuation.definition.string.begin.fsharp
      push:
        - meta_scope: string.quoted.double.fsharp
        - match: (")
          captures:
            1: punctuation.definition.string.end.fsharp
          pop: true
        - match: '\\$[ \t]*'
          scope: punctuation.separator.string.ignore-eol.fsharp
        - match: '\\([\\''''ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8})'
          scope: constant.character.string.escape.fsharp
        - match: '\\(?![\\''''ntbr]|u[a-fA-F0-9]{4}|u[a-fA-F0-9]{8}).'
          scope: invalid.illeagal.character.string.fsharp
        - include: string_formatter
  strp_inlined:
    - match: (\()
      captures:
        1: keyword.symbol.fsharp
      push:
        - match: (\))
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - include: strp_inlined_body
  strp_inlined_body:
    - include: comments
    - include: anonymous_functions
    - match: '(\^[[:alpha:]0-9''._]+)'
      captures:
        1: entity.name.type.fsharp
    - match: \b(and|when|or)\b
      scope: keyword.fsharp
    - match: (\()
      captures:
        1: keyword.symbol.fsharp
      push:
        - match: (\))
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - include: strp_inlined_body
    - match: '(static member|member)\s*([[:alpha:]0-9''`<>^._]+|``[[:alpha:]0-9'' <>^._]+``)\s*(:)'
      captures:
        1: keyword.fsharp
        2: variable.fsharp
        3: keyword.symbol.fsharp
    - include: compiler_directives
    - include: constants
    - include: strings
    - include: chars
    - include: double_tick
    - include: keywords
    - include: text
    - include: definition
    - include: attributes
    - include: keywords
    - include: cexprs
    - include: text
  text:
    - match: \\
      scope: text.fsharp
  tuple_signature:
    - match: "(([?[:alpha:]0-9'`^._ ]+))+"
      captures:
        1: entity.name.type.fsharp
    - match: (\()
      captures:
        1: keyword.symbol.fsharp
      push:
        - match: (\))
          captures:
            1: keyword.symbol.fsharp
          pop: true
        - match: "(([?[:alpha:]0-9'`^._ ]+))+"
          captures:
            1: entity.name.type.fsharp
        - include: tuple_signature
    - include: keywords
  variables:
    - match: \(\)
      scope: constant.language.unit.fsharp
    - match: '(\?{0,1})(``[[:alpha:]0-9''`^:,._ ]+``|[[:alpha:]0-9''`<>^._ ]\w*)'
      captures:
        1: keyword.symbol.fsharp
        2: variable.parameter.fsharp