1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
# -*- coding: utf-8 -*- #
# frozen_string_literal: true
module Rouge
module Lexers
# Direct port of pygments Lexer.
# See: https://bitbucket.org/birkenfeld/pygments-main/src/7304e4759ae65343d89a51359ca538912519cc31/pygments/lexers/functional.py?at=default#cl-2362
class Elixir < RegexLexer
title "Elixir"
desc "Elixir language (elixir-lang.org)"
tag 'elixir'
aliases 'elixir', 'exs'
filenames '*.ex', '*.exs'
def self.detect?(text)
return true if text.shebang?('elixir')
end
mimetypes 'text/x-elixir', 'application/x-elixir'
state :root do
rule %r/\s+/m, Text
rule %r/#.*$/, Comment::Single
rule %r{\b(case|cond|end|bc|lc|if|unless|try|loop|receive|fn|defmodule|
defp?|defprotocol|defimpl|defrecord|defmacrop?|defdelegate|
defexception|defguardp?|defstruct|exit|raise|throw|after|rescue|catch|else)\b(?![?!])|
(?<!\.)\b(do|\-\>)\b}x, Keyword
rule %r/\b(import|require|use|recur|quote|unquote|super|refer)\b(?![?!])/, Keyword::Namespace
rule %r/(?<!\.)\b(and|not|or|when|xor|in)\b/, Operator::Word
rule %r{%=|\*=|\*\*=|\+=|\-=|\^=|\|\|=|
<=>|<(?!<|=)|>(?!<|=|>)|<=|>=|===|==|=~|!=|!~|(?=[\s])\?|
(?<=[\s])!+|&(&&?|(?!\d))|\|\||\^|\*|\+|\-|/|
\||\+\+|\-\-|\*\*|\/\/|\<\-|\<\>|<<|>>|=|\.|~~~}x, Operator
rule %r{(?<!:)(:)([a-zA-Z_]\w*([?!]|=(?![>=]))?|\<\>|===?|>=?|<=?|
<=>|&&?|%\(\)|%\[\]|%\{\}|\+\+?|\-\-?|\|\|?|\!|//|[%&`/\|]|
\*\*?|=?~|<\-)|([a-zA-Z_]\w*([?!])?)(:)(?!:)}, Str::Symbol
rule %r/:"/, Str::Symbol, :interpoling_symbol
rule %r/\b(nil|true|false)\b(?![?!])|\b[A-Z]\w*\b/, Name::Constant
rule %r/\b(__(FILE|LINE|MODULE|MAIN|FUNCTION)__)\b(?![?!])/, Name::Builtin::Pseudo
rule %r/[a-zA-Z_!]\w*[!\?]?/, Name
rule %r{::|[%(){};,/\|:\\\[\]]}, Punctuation
rule %r/@[a-zA-Z_]\w*|&\d/, Name::Variable
rule %r{\b\d(_?\d)*(\.(?![^\d\s])(_?\d)+)([eE][-+]?\d(_?\d)*)?\b}, Num::Float
rule %r{\b0x[0-9A-Fa-f](_?[0-9A-Fa-f])*\b}, Num::Hex
rule %r{\b0o[0-7](_?[0-7])*\b}, Num::Oct
rule %r{\b0b[01](_?[01])*\b}, Num::Bin
rule %r{\b\d(_?\d)*\b}, Num::Integer
mixin :strings
mixin :sigil_strings
end
state :strings do
rule %r/(%[A-Ba-z])?"""(?:.|\n)*?"""/, Str::Doc
rule %r/'''(?:.|\n)*?'''/, Str::Doc
rule %r/"/, Str::Double, :dqs
rule %r/'/, Str::Single, :sqs
rule %r{(?<!\w)\?(\\(x\d{1,2}|\h{1,2}(?!\h)\b|0[0-7]{0,2}(?![0-7])\b[^x0MC])|(\\[MC]-)+\w|[^\s\\])}, Str::Other
end
state :dqs do
mixin :escapes
mixin :interpoling
rule %r/[^#"\\]+/, Str::Double
rule %r/"/, Str::Double, :pop!
rule %r/[#\\]/, Str::Double
end
state :sqs do
mixin :escapes
mixin :interpoling
rule %r/[^#'\\]+/, Str::Single
rule %r/'/, Str::Single, :pop!
rule %r/[#\\]/, Str::Single
end
state :interpoling do
rule %r/#\{/, Str::Interpol, :interpoling_string
end
state :interpoling_string do
rule %r/\}/, Str::Interpol, :pop!
mixin :root
end
state :escapes do
rule %r/\\x\h{2}/, Str::Escape
rule %r/\\u\{?\d+\}?/, Str::Escape
rule %r/\\[\\abdefnrstv0"']/, Str::Escape
end
state :interpoling_symbol do
rule %r/"/, Str::Symbol, :pop!
mixin :interpoling
rule %r/[^#"]+/, Str::Symbol
end
state :sigil_strings do
# ~-sigiled strings
# ~(abc), ~[abc], ~<abc>, ~|abc|, ~r/abc/, etc
# Cribbed and adjusted from Ruby lexer
delimiter_map = { '{' => '}', '[' => ']', '(' => ')', '<' => '>' }
# Match a-z for custom sigils too
sigil_opens = Regexp.union(delimiter_map.keys + %w(| / ' "))
rule %r/~([A-Za-z])?(#{sigil_opens})/ do |m|
open = Regexp.escape(m[2])
close = Regexp.escape(delimiter_map[m[2]] || m[2])
interp = /[SRCW]/ === m[1]
toktype = Str::Other
puts " open: #{open.inspect}" if @debug
puts " close: #{close.inspect}" if @debug
# regexes
if 'Rr'.include? m[1]
toktype = Str::Regex
push :regex_flags
end
if 'Ww'.include? m[1]
push :list_flags
end
token toktype
push do
rule %r/#{close}/, toktype, :pop!
if interp
mixin :interpoling
rule %r/#/, toktype
else
rule %r/[\\#]/, toktype
end
uniq_chars = [open, close].uniq.join
rule %r/[^##{uniq_chars}\\]+/m, toktype
end
end
end
state :regex_flags do
rule %r/[fgimrsux]*/, Str::Regex, :pop!
end
state :list_flags do
rule %r/[csa]?/, Str::Other, :pop!
end
end
end
end
|