]> luflow.net public git repositories - flow-web.git/blob - static/highlight/languages/elixir.js
Initial commit.
[flow-web.git] / static / highlight / languages / elixir.js
1 /*! `elixir` grammar compiled for Highlight.js 11.11.1 */
2 (function(){
3 var hljsGrammar = (function () {
4 'use strict';
5
6 /*
7 Language: Elixir
8 Author: Josh Adams <josh@isotope11.com>
9 Description: language definition for Elixir source code files (.ex and .exs). Based on ruby language support.
10 Category: functional
11 Website: https://elixir-lang.org
12 */
13
14 /** @type LanguageFn */
15 function elixir(hljs) {
16 const regex = hljs.regex;
17 const ELIXIR_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_.]*(!|\\?)?';
18 const ELIXIR_METHOD_RE = '[a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?';
19 const KEYWORDS = [
20 "after",
21 "alias",
22 "and",
23 "case",
24 "catch",
25 "cond",
26 "defstruct",
27 "defguard",
28 "do",
29 "else",
30 "end",
31 "fn",
32 "for",
33 "if",
34 "import",
35 "in",
36 "not",
37 "or",
38 "quote",
39 "raise",
40 "receive",
41 "require",
42 "reraise",
43 "rescue",
44 "try",
45 "unless",
46 "unquote",
47 "unquote_splicing",
48 "use",
49 "when",
50 "with|0"
51 ];
52 const LITERALS = [
53 "false",
54 "nil",
55 "true"
56 ];
57 const KWS = {
58 $pattern: ELIXIR_IDENT_RE,
59 keyword: KEYWORDS,
60 literal: LITERALS
61 };
62 const SUBST = {
63 className: 'subst',
64 begin: /#\{/,
65 end: /\}/,
66 keywords: KWS
67 };
68 const NUMBER = {
69 className: 'number',
70 begin: '(\\b0o[0-7_]+)|(\\b0b[01_]+)|(\\b0x[0-9a-fA-F_]+)|(-?\\b[0-9][0-9_]*(\\.[0-9_]+([eE][-+]?[0-9]+)?)?)',
71 relevance: 0
72 };
73 // TODO: could be tightened
74 // https://elixir-lang.readthedocs.io/en/latest/intro/18.html
75 // but you also need to include closing delemeters in the escape list per
76 // individual sigil mode from what I can tell,
77 // ie: \} might or might not be an escape depending on the sigil used
78 const ESCAPES_RE = /\\[\s\S]/;
79 // const ESCAPES_RE = /\\["'\\abdefnrstv0]/;
80 const BACKSLASH_ESCAPE = {
81 match: ESCAPES_RE,
82 scope: "char.escape",
83 relevance: 0
84 };
85 const SIGIL_DELIMITERS = '[/|([{<"\']';
86 const SIGIL_DELIMITER_MODES = [
87 {
88 begin: /"/,
89 end: /"/
90 },
91 {
92 begin: /'/,
93 end: /'/
94 },
95 {
96 begin: /\//,
97 end: /\//
98 },
99 {
100 begin: /\|/,
101 end: /\|/
102 },
103 {
104 begin: /\(/,
105 end: /\)/
106 },
107 {
108 begin: /\[/,
109 end: /\]/
110 },
111 {
112 begin: /\{/,
113 end: /\}/
114 },
115 {
116 begin: /</,
117 end: />/
118 }
119 ];
120 const escapeSigilEnd = (end) => {
121 return {
122 scope: "char.escape",
123 begin: regex.concat(/\\/, end),
124 relevance: 0
125 };
126 };
127 const LOWERCASE_SIGIL = {
128 className: 'string',
129 begin: '~[a-z]' + '(?=' + SIGIL_DELIMITERS + ')',
130 contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x,
131 { contains: [
132 escapeSigilEnd(x.end),
133 BACKSLASH_ESCAPE,
134 SUBST
135 ] }
136 ))
137 };
138
139 const UPCASE_SIGIL = {
140 className: 'string',
141 begin: '~[A-Z]' + '(?=' + SIGIL_DELIMITERS + ')',
142 contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x,
143 { contains: [ escapeSigilEnd(x.end) ] }
144 ))
145 };
146
147 const REGEX_SIGIL = {
148 className: 'regex',
149 variants: [
150 {
151 begin: '~r' + '(?=' + SIGIL_DELIMITERS + ')',
152 contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x,
153 {
154 end: regex.concat(x.end, /[uismxfU]{0,7}/),
155 contains: [
156 escapeSigilEnd(x.end),
157 BACKSLASH_ESCAPE,
158 SUBST
159 ]
160 }
161 ))
162 },
163 {
164 begin: '~R' + '(?=' + SIGIL_DELIMITERS + ')',
165 contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x,
166 {
167 end: regex.concat(x.end, /[uismxfU]{0,7}/),
168 contains: [ escapeSigilEnd(x.end) ]
169 })
170 )
171 }
172 ]
173 };
174
175 const STRING = {
176 className: 'string',
177 contains: [
178 hljs.BACKSLASH_ESCAPE,
179 SUBST
180 ],
181 variants: [
182 {
183 begin: /"""/,
184 end: /"""/
185 },
186 {
187 begin: /'''/,
188 end: /'''/
189 },
190 {
191 begin: /~S"""/,
192 end: /"""/,
193 contains: [] // override default
194 },
195 {
196 begin: /~S"/,
197 end: /"/,
198 contains: [] // override default
199 },
200 {
201 begin: /~S'''/,
202 end: /'''/,
203 contains: [] // override default
204 },
205 {
206 begin: /~S'/,
207 end: /'/,
208 contains: [] // override default
209 },
210 {
211 begin: /'/,
212 end: /'/
213 },
214 {
215 begin: /"/,
216 end: /"/
217 }
218 ]
219 };
220 const FUNCTION = {
221 className: 'function',
222 beginKeywords: 'def defp defmacro defmacrop',
223 end: /\B\b/, // the mode is ended by the title
224 contains: [
225 hljs.inherit(hljs.TITLE_MODE, {
226 begin: ELIXIR_IDENT_RE,
227 endsParent: true
228 })
229 ]
230 };
231 const CLASS = hljs.inherit(FUNCTION, {
232 className: 'class',
233 beginKeywords: 'defimpl defmodule defprotocol defrecord',
234 end: /\bdo\b|$|;/
235 });
236 const ELIXIR_DEFAULT_CONTAINS = [
237 STRING,
238 REGEX_SIGIL,
239 UPCASE_SIGIL,
240 LOWERCASE_SIGIL,
241 hljs.HASH_COMMENT_MODE,
242 CLASS,
243 FUNCTION,
244 { begin: '::' },
245 {
246 className: 'symbol',
247 begin: ':(?![\\s:])',
248 contains: [
249 STRING,
250 { begin: ELIXIR_METHOD_RE }
251 ],
252 relevance: 0
253 },
254 {
255 className: 'symbol',
256 begin: ELIXIR_IDENT_RE + ':(?!:)',
257 relevance: 0
258 },
259 { // Usage of a module, struct, etc.
260 className: 'title.class',
261 begin: /(\b[A-Z][a-zA-Z0-9_]+)/,
262 relevance: 0
263 },
264 NUMBER,
265 {
266 className: 'variable',
267 begin: '(\\$\\W)|((\\$|@@?)(\\w+))'
268 }
269 // -> has been removed, capnproto always uses this grammar construct
270 ];
271 SUBST.contains = ELIXIR_DEFAULT_CONTAINS;
272
273 return {
274 name: 'Elixir',
275 aliases: [
276 'ex',
277 'exs'
278 ],
279 keywords: KWS,
280 contains: ELIXIR_DEFAULT_CONTAINS
281 };
282 }
283
284 return elixir;
285
286 })();
287
288 hljs.registerLanguage('elixir', hljsGrammar);
289 })();