;;; Identifiers

(identifier) @variable

; ;; If you want type highlighting based on Julia naming conventions (this might collide with mathematical notation)
; ((identifier) @type
;   (match? @type "^[A-Z][^_]"))  ; exception: Highlight `A_foo` sort of identifiers as variables

(macro_identifier) @function.macro
(macro_identifier
  (identifier) @function.macro) ; for any one using the variable highlight

(macro_definition
  name: (identifier) @function.macro)

(quote_expression
  ":" @symbol
  [(identifier) (operator)] @symbol)

(field_expression
  (identifier) @field .)


;;; Function names

;; Definitions

(function_definition
  name: (identifier) @function)
(short_function_definition
  name: (identifier) @function)

(function_definition
  name: (field_expression (identifier) @function .))
(short_function_definition
  name: (field_expression (identifier) @function .))

;; calls

(call_expression
  (identifier) @function.call)
(call_expression
  (field_expression (identifier) @function.call .))

(broadcast_call_expression
  (identifier) @function.call)
(broadcast_call_expression
  (field_expression (identifier) @function.call .))

(binary_expression
  (_)
  (operator) @_pipe
  (identifier) @function.call
  (#eq? @_pipe "|>"))

;; Builtins

((identifier) @function.builtin
  (#any-of? @function.builtin
  "_abstracttype" "_apply_iterate" "_apply_pure" "_call_in_world" "_call_in_world_total"
  "_call_latest" "_equiv_typedef" "_expr" "_primitivetype" "_setsuper!" "_structtype"
  "_typebody!" "_typevar" "applicable" "apply_type" "arrayref" "arrayset" "arraysize"
  "const_arrayref" "donotdelete" "fieldtype" "get_binding_type" "getfield" "ifelse" "invoke" "isa"
  "isdefined" "modifyfield!" "nfields" "replacefield!" "set_binding_type!" "setfield!" "sizeof"
  "svec" "swapfield!" "throw" "tuple" "typeassert" "typeof"))


;;; Parameters

(parameter_list
  (identifier) @parameter)
(optional_parameter .
  (identifier) @parameter)
(slurp_parameter
  (identifier) @parameter)

(typed_parameter
  parameter: (identifier)? @parameter
  type: (_) @type)

(function_expression
  . (identifier) @parameter) ; Single parameter arrow functions


;;; Types

;; Definitions

(abstract_definition
  name: (identifier) @type.definition) @keyword
(primitive_definition
  name: (identifier) @type.definition) @keyword
(struct_definition
  name: (identifier) @type)
(type_clause
  [(identifier) @type
    (field_expression (identifier) @type .)])

;; Annotations

(parametrized_type_expression
  (_) @type
  (curly_expression (_) @type))

(type_parameter_list
  (identifier) @type)

(typed_expression
  (identifier) @type .)

(function_definition
  return_type: (identifier) @type)
(short_function_definition
  return_type: (identifier) @type)

(where_clause
  (identifier) @type)
(where_clause
  (curly_expression (_) @type))

;; Builtins

;; This list was generated with:
;;
;;  istype(x) = typeof(x) === DataType || typeof(x) === UnionAll
;;  get_types(m) = filter(x -> istype(Base.eval(m, x)), names(m))
;;  type_names = sort(union(get_types(Core), get_types(Base)))
;;
((identifier) @type.builtin
 (#any-of? @type.builtin
  "AbstractArray"
  "AbstractChannel"
  "AbstractChar"
  "AbstractDict"
  "AbstractDisplay"
  "AbstractFloat"
  "AbstractIrrational"
  "AbstractLock"
  "AbstractMatch"
  "AbstractMatrix"
  "AbstractPattern"
  "AbstractRange"
  "AbstractSet"
  "AbstractSlices"
  "AbstractString"
  "AbstractUnitRange"
  "AbstractVecOrMat"
  "AbstractVector"
  "Any"
  "ArgumentError"
  "Array"
  "AssertionError"
  "Atomic"
  "BigFloat"
  "BigInt"
  "BitArray"
  "BitMatrix"
  "BitSet"
  "BitVector"
  "Bool"
  "BoundsError"
  "By"
  "CanonicalIndexError"
  "CapturedException"
  "CartesianIndex"
  "CartesianIndices"
  "Cchar"
  "Cdouble"
  "Cfloat"
  "Channel"
  "Char"
  "Cint"
  "Cintmax_t"
  "Clong"
  "Clonglong"
  "Cmd"
  "Colon"
  "ColumnSlices"
  "Complex"
  "ComplexF16"
  "ComplexF32"
  "ComplexF64"
  "ComposedFunction"
  "CompositeException"
  "ConcurrencyViolationError"
  "Condition"
  "Cptrdiff_t"
  "Cshort"
  "Csize_t"
  "Cssize_t"
  "Cstring"
  "Cuchar"
  "Cuint"
  "Cuintmax_t"
  "Culong"
  "Culonglong"
  "Cushort"
  "Cvoid"
  "Cwchar_t"
  "Cwstring"
  "DataType"
  "DenseArray"
  "DenseMatrix"
  "DenseVecOrMat"
  "DenseVector"
  "Dict"
  "DimensionMismatch"
  "Dims"
  "DivideError"
  "DomainError"
  "EOFError"
  "Enum"
  "ErrorException"
  "Exception"
  "ExponentialBackOff"
  "Expr"
  "Float16"
  "Float32"
  "Float64"
  "Function"
  "GlobalRef"
  "HTML"
  "IO"
  "IOBuffer"
  "IOContext"
  "IOStream"
  "IdDict"
  "IndexCartesian"
  "IndexLinear"
  "IndexStyle"
  "InexactError"
  "InitError"
  "Int"
  "Int128"
  "Int16"
  "Int32"
  "Int64"
  "Int8"
  "Integer"
  "InterruptException"
  "InvalidStateException"
  "Irrational"
  "KeyError"
  "LazyString"
  "LinRange"
  "LineNumberNode"
  "LinearIndices"
  "LoadError"
  "Lt"
  "MIME"
  "Matrix"
  "Method"
  "MethodError"
  "Missing"
  "MissingException"
  "Module"
  "NTuple"
  "NamedTuple"
  "Nothing"
  "Number"
  "Ordering"
  "OrdinalRange"
  "OutOfMemoryError"
  "OverflowError"
  "Pair"
  "ParseError"
  "PartialQuickSort"
  "Perm"
  "PermutedDimsArray"
  "Pipe"
  "ProcessFailedException"
  "Ptr"
  "QuoteNode"
  "Rational"
  "RawFD"
  "ReadOnlyMemoryError"
  "Real"
  "ReentrantLock"
  "Ref"
  "Regex"
  "RegexMatch"
  "Returns"
  "ReverseOrdering"
  "RoundingMode"
  "RowSlices"
  "SegmentationFault"
  "Set"
  "Signed"
  "Slices"
  "Some"
  "SpinLock"
  "StackFrame"
  "StackOverflowError"
  "StackTrace"
  "Stateful"
  "StepRange"
  "StepRangeLen"
  "StridedArray"
  "StridedMatrix"
  "StridedVecOrMat"
  "StridedVector"
  "String"
  "StringIndexError"
  "SubArray"
  "SubString"
  "SubstitutionString"
  "Symbol"
  "SystemError"
  "Task"
  "TaskFailedException"
  "Text"
  "TextDisplay"
  "Timer"
  "Tmstruct"
  "Tuple"
  "Type"
  "TypeError"
  "TypeVar"
  "UInt"
  "UInt128"
  "UInt16"
  "UInt32"
  "UInt64"
  "UInt8"
  "UndefInitializer"
  "UndefKeywordError"
  "UndefRefError"
  "UndefVarError"
  "Union"
  "UnionAll"
  "UnitRange"
  "Unsigned"
  "Val"
  "VecElement"
  "VecOrMat"
  "Vector"
  "VersionNumber"
  "WeakKeyDict"
  "WeakRef"))

((identifier) @variable.builtin
  (#any-of? @variable.builtin "begin" "end")
  (#has-ancestor? @variable.builtin index_expression))

((identifier) @variable.builtin
  (#any-of? @variable.builtin "begin" "end")
  (#has-ancestor? @variable.builtin range_expression))

;;; Keywords

[
  "global"
  "local"
] @keyword


(compound_statement
  ["begin" "end"] @keyword)
(quote_statement
  ["quote" "end"] @keyword)
(let_statement
  ["let" "end"] @keyword)

(if_statement
  ["if" "end"] @conditional)
(elseif_clause
  "elseif" @conditional)
(else_clause
  "else" @conditional)
(if_clause
  "if" @conditional) ; `if` clause in comprehensions
(ternary_expression
  ["?" ":"] @conditional.ternary)

(try_statement
  ["try" "end"] @exception)
(finally_clause
  "finally" @exception)
(catch_clause
  "catch" @exception)

(for_statement
  ["for" "end"] @repeat)
(while_statement
  ["while" "end"] @repeat)
(for_clause
  "for" @repeat)
[
  (break_statement)
  (continue_statement)
] @repeat

(module_definition
  ["module" "baremodule" "end"] @include)
(import_statement
  ["import" "using"] @include)
(import_alias
  "as" @include)
(export_statement
  "export" @include)
(selected_import
  ":" @punctuation.delimiter)

(struct_definition
  ["struct" "end"] @keyword)

(macro_definition
  ["macro" "end"] @keyword)

(function_definition
  ["function" "end"] @keyword.function)
(do_clause
  ["do" "end"] @keyword.function)
(return_statement
  "return" @keyword.return)

[
  "const"
  "mutable"
] @type.qualifier


;;; Operators & Punctuation

[
  "="
  "∈"
  (operator)
] @operator

(adjoint_expression "'" @operator)
(range_expression ":" @operator)

((operator) @keyword.operator
  (#any-of? @keyword.operator "in" "isa"))

(for_binding "in" @keyword.operator)

(where_clause "where" @keyword.operator)
(where_expression "where" @keyword.operator)

[
  ","
  "."
  ";"
  "::"
  "->"
] @punctuation.delimiter

[
  "..."
] @punctuation.special

["(" ")" "[" "]" "{" "}"] @punctuation.bracket


;;; Literals

(boolean_literal) @boolean
(integer_literal) @number
(float_literal) @float

((identifier) @float
  (#any-of? @float "NaN" "NaN16" "NaN32"
                   "Inf" "Inf16" "Inf32"))

((identifier) @constant.builtin
  (#any-of? @constant.builtin "nothing" "missing"))

(character_literal) @character
(escape_sequence) @string.escape

(string_literal) @string
(prefixed_string_literal
  prefix: (identifier) @function.macro) @string

(command_literal) @string.special
(prefixed_command_literal
  prefix: (identifier) @function.macro) @string.special

((string_literal) @string.documentation @spell
  . [
      (module_definition)
      (abstract_definition)
      (struct_definition)
      (function_definition)
      (short_function_definition)
      (assignment)
      (const_statement)
    ])

[
  (line_comment)
  (block_comment)
] @comment @spell

