]> luflow.net public git repositories - flow-web.git/blob - static/highlight/es/languages/fsharp.js
Initial commit.
[flow-web.git] / static / highlight / es / languages / fsharp.js
1 /*! `fsharp` grammar compiled for Highlight.js 11.11.1 */
2 var hljsGrammar = (function () {
3 'use strict';
4
5 /**
6 * @param {string} value
7 * @returns {RegExp}
8 * */
9 function escape(value) {
10 return new RegExp(value.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'), 'm');
11 }
12
13 /**
14 * @param {RegExp | string } re
15 * @returns {string}
16 */
17 function source(re) {
18 if (!re) return null;
19 if (typeof re === "string") return re;
20
21 return re.source;
22 }
23
24 /**
25 * @param {RegExp | string } re
26 * @returns {string}
27 */
28 function lookahead(re) {
29 return concat('(?=', re, ')');
30 }
31
32 /**
33 * @param {...(RegExp | string) } args
34 * @returns {string}
35 */
36 function concat(...args) {
37 const joined = args.map((x) => source(x)).join("");
38 return joined;
39 }
40
41 /**
42 * @param { Array<string | RegExp | Object> } args
43 * @returns {object}
44 */
45 function stripOptionsFromArgs(args) {
46 const opts = args[args.length - 1];
47
48 if (typeof opts === 'object' && opts.constructor === Object) {
49 args.splice(args.length - 1, 1);
50 return opts;
51 } else {
52 return {};
53 }
54 }
55
56 /** @typedef { {capture?: boolean} } RegexEitherOptions */
57
58 /**
59 * Any of the passed expresssions may match
60 *
61 * Creates a huge this | this | that | that match
62 * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args
63 * @returns {string}
64 */
65 function either(...args) {
66 /** @type { object & {capture?: boolean} } */
67 const opts = stripOptionsFromArgs(args);
68 const joined = '('
69 + (opts.capture ? "" : "?:")
70 + args.map((x) => source(x)).join("|") + ")";
71 return joined;
72 }
73
74 /*
75 Language: F#
76 Author: Jonas Follesø <jonas@follesoe.no>
77 Contributors: Troy Kershaw <hello@troykershaw.com>, Henrik Feldt <henrik@haf.se>, Melvyn Laïly <melvyn.laily@gmail.com>
78 Website: https://docs.microsoft.com/en-us/dotnet/fsharp/
79 Category: functional
80 */
81
82
83 /** @type LanguageFn */
84 function fsharp(hljs) {
85 const KEYWORDS = [
86 "abstract",
87 "and",
88 "as",
89 "assert",
90 "base",
91 "begin",
92 "class",
93 "default",
94 "delegate",
95 "do",
96 "done",
97 "downcast",
98 "downto",
99 "elif",
100 "else",
101 "end",
102 "exception",
103 "extern",
104 // "false", // literal
105 "finally",
106 "fixed",
107 "for",
108 "fun",
109 "function",
110 "global",
111 "if",
112 "in",
113 "inherit",
114 "inline",
115 "interface",
116 "internal",
117 "lazy",
118 "let",
119 "match",
120 "member",
121 "module",
122 "mutable",
123 "namespace",
124 "new",
125 // "not", // built_in
126 // "null", // literal
127 "of",
128 "open",
129 "or",
130 "override",
131 "private",
132 "public",
133 "rec",
134 "return",
135 "static",
136 "struct",
137 "then",
138 "to",
139 // "true", // literal
140 "try",
141 "type",
142 "upcast",
143 "use",
144 "val",
145 "void",
146 "when",
147 "while",
148 "with",
149 "yield"
150 ];
151
152 const BANG_KEYWORD_MODE = {
153 // monad builder keywords (matches before non-bang keywords)
154 scope: 'keyword',
155 match: /\b(yield|return|let|do|match|use)!/
156 };
157
158 const PREPROCESSOR_KEYWORDS = [
159 "if",
160 "else",
161 "endif",
162 "line",
163 "nowarn",
164 "light",
165 "r",
166 "i",
167 "I",
168 "load",
169 "time",
170 "help",
171 "quit"
172 ];
173
174 const LITERALS = [
175 "true",
176 "false",
177 "null",
178 "Some",
179 "None",
180 "Ok",
181 "Error",
182 "infinity",
183 "infinityf",
184 "nan",
185 "nanf"
186 ];
187
188 const SPECIAL_IDENTIFIERS = [
189 "__LINE__",
190 "__SOURCE_DIRECTORY__",
191 "__SOURCE_FILE__"
192 ];
193
194 // Since it's possible to re-bind/shadow names (e.g. let char = 'c'),
195 // these builtin types should only be matched when a type name is expected.
196 const KNOWN_TYPES = [
197 // basic types
198 "bool",
199 "byte",
200 "sbyte",
201 "int8",
202 "int16",
203 "int32",
204 "uint8",
205 "uint16",
206 "uint32",
207 "int",
208 "uint",
209 "int64",
210 "uint64",
211 "nativeint",
212 "unativeint",
213 "decimal",
214 "float",
215 "double",
216 "float32",
217 "single",
218 "char",
219 "string",
220 "unit",
221 "bigint",
222 // other native types or lowercase aliases
223 "option",
224 "voption",
225 "list",
226 "array",
227 "seq",
228 "byref",
229 "exn",
230 "inref",
231 "nativeptr",
232 "obj",
233 "outref",
234 "voidptr",
235 // other important FSharp types
236 "Result"
237 ];
238
239 const BUILTINS = [
240 // Somewhat arbitrary list of builtin functions and values.
241 // Most of them are declared in Microsoft.FSharp.Core
242 // I tried to stay relevant by adding only the most idiomatic
243 // and most used symbols that are not already declared as types.
244 "not",
245 "ref",
246 "raise",
247 "reraise",
248 "dict",
249 "readOnlyDict",
250 "set",
251 "get",
252 "enum",
253 "sizeof",
254 "typeof",
255 "typedefof",
256 "nameof",
257 "nullArg",
258 "invalidArg",
259 "invalidOp",
260 "id",
261 "fst",
262 "snd",
263 "ignore",
264 "lock",
265 "using",
266 "box",
267 "unbox",
268 "tryUnbox",
269 "printf",
270 "printfn",
271 "sprintf",
272 "eprintf",
273 "eprintfn",
274 "fprintf",
275 "fprintfn",
276 "failwith",
277 "failwithf"
278 ];
279
280 const ALL_KEYWORDS = {
281 keyword: KEYWORDS,
282 literal: LITERALS,
283 built_in: BUILTINS,
284 'variable.constant': SPECIAL_IDENTIFIERS
285 };
286
287 // (* potentially multi-line Meta Language style comment *)
288 const ML_COMMENT =
289 hljs.COMMENT(/\(\*(?!\))/, /\*\)/, {
290 contains: ["self"]
291 });
292 // Either a multi-line (* Meta Language style comment *) or a single line // C style comment.
293 const COMMENT = {
294 variants: [
295 ML_COMMENT,
296 hljs.C_LINE_COMMENT_MODE,
297 ]
298 };
299
300 // Most identifiers can contain apostrophes
301 const IDENTIFIER_RE = /[a-zA-Z_](\w|')*/;
302
303 const QUOTED_IDENTIFIER = {
304 scope: 'variable',
305 begin: /``/,
306 end: /``/
307 };
308
309 // 'a or ^a where a can be a ``quoted identifier``
310 const BEGIN_GENERIC_TYPE_SYMBOL_RE = /\B('|\^)/;
311 const GENERIC_TYPE_SYMBOL = {
312 scope: 'symbol',
313 variants: [
314 // the type name is a quoted identifier:
315 { match: concat(BEGIN_GENERIC_TYPE_SYMBOL_RE, /``.*?``/) },
316 // the type name is a normal identifier (we don't use IDENTIFIER_RE because there cannot be another apostrophe here):
317 { match: concat(BEGIN_GENERIC_TYPE_SYMBOL_RE, hljs.UNDERSCORE_IDENT_RE) }
318 ],
319 relevance: 0
320 };
321
322 const makeOperatorMode = function({ includeEqual }) {
323 // List or symbolic operator characters from the FSharp Spec 4.1, minus the dot, and with `?` added, used for nullable operators.
324 let allOperatorChars;
325 if (includeEqual)
326 allOperatorChars = "!%&*+-/<=>@^|~?";
327 else
328 allOperatorChars = "!%&*+-/<>@^|~?";
329 const OPERATOR_CHARS = Array.from(allOperatorChars);
330 const OPERATOR_CHAR_RE = concat('[', ...OPERATOR_CHARS.map(escape), ']');
331 // The lone dot operator is special. It cannot be redefined, and we don't want to highlight it. It can be used as part of a multi-chars operator though.
332 const OPERATOR_CHAR_OR_DOT_RE = either(OPERATOR_CHAR_RE, /\./);
333 // When a dot is present, it must be followed by another operator char:
334 const OPERATOR_FIRST_CHAR_OF_MULTIPLE_RE = concat(OPERATOR_CHAR_OR_DOT_RE, lookahead(OPERATOR_CHAR_OR_DOT_RE));
335 const SYMBOLIC_OPERATOR_RE = either(
336 concat(OPERATOR_FIRST_CHAR_OF_MULTIPLE_RE, OPERATOR_CHAR_OR_DOT_RE, '*'), // Matches at least 2 chars operators
337 concat(OPERATOR_CHAR_RE, '+'), // Matches at least one char operators
338 );
339 return {
340 scope: 'operator',
341 match: either(
342 // symbolic operators:
343 SYMBOLIC_OPERATOR_RE,
344 // other symbolic keywords:
345 // Type casting and conversion operators:
346 /:\?>/,
347 /:\?/,
348 /:>/,
349 /:=/, // Reference cell assignment
350 /::?/, // : or ::
351 /\$/), // A single $ can be used as an operator
352 relevance: 0
353 };
354 };
355
356 const OPERATOR = makeOperatorMode({ includeEqual: true });
357 // This variant is used when matching '=' should end a parent mode:
358 const OPERATOR_WITHOUT_EQUAL = makeOperatorMode({ includeEqual: false });
359
360 const makeTypeAnnotationMode = function(prefix, prefixScope) {
361 return {
362 begin: concat( // a type annotation is a
363 prefix, // should be a colon or the 'of' keyword
364 lookahead( // that has to be followed by
365 concat(
366 /\s*/, // optional space
367 either( // then either of:
368 /\w/, // word
369 /'/, // generic type name
370 /\^/, // generic type name
371 /#/, // flexible type name
372 /``/, // quoted type name
373 /\(/, // parens type expression
374 /{\|/, // anonymous type annotation
375 )))),
376 beginScope: prefixScope,
377 // BUG: because ending with \n is necessary for some cases, multi-line type annotations are not properly supported.
378 // Examples where \n is required at the end:
379 // - abstract member definitions in classes: abstract Property : int * string
380 // - return type annotations: let f f' = f' () : returnTypeAnnotation
381 // - record fields definitions: { A : int \n B : string }
382 end: lookahead(
383 either(
384 /\n/,
385 /=/)),
386 relevance: 0,
387 // we need the known types, and we need the type constraint keywords and literals. e.g.: when 'a : null
388 keywords: hljs.inherit(ALL_KEYWORDS, { type: KNOWN_TYPES }),
389 contains: [
390 COMMENT,
391 GENERIC_TYPE_SYMBOL,
392 hljs.inherit(QUOTED_IDENTIFIER, { scope: null }), // match to avoid strange patterns inside that may break the parsing
393 OPERATOR_WITHOUT_EQUAL
394 ]
395 };
396 };
397
398 const TYPE_ANNOTATION = makeTypeAnnotationMode(/:/, 'operator');
399 const DISCRIMINATED_UNION_TYPE_ANNOTATION = makeTypeAnnotationMode(/\bof\b/, 'keyword');
400
401 // type MyType<'a> = ...
402 const TYPE_DECLARATION = {
403 begin: [
404 /(^|\s+)/, // prevents matching the following: `match s.stype with`
405 /type/,
406 /\s+/,
407 IDENTIFIER_RE
408 ],
409 beginScope: {
410 2: 'keyword',
411 4: 'title.class'
412 },
413 end: lookahead(/\(|=|$/),
414 keywords: ALL_KEYWORDS, // match keywords in type constraints. e.g.: when 'a : null
415 contains: [
416 COMMENT,
417 hljs.inherit(QUOTED_IDENTIFIER, { scope: null }), // match to avoid strange patterns inside that may break the parsing
418 GENERIC_TYPE_SYMBOL,
419 {
420 // For visual consistency, highlight type brackets as operators.
421 scope: 'operator',
422 match: /<|>/
423 },
424 TYPE_ANNOTATION // generic types can have constraints, which are type annotations. e.g. type MyType<'T when 'T : delegate<obj * string>> =
425 ]
426 };
427
428 const COMPUTATION_EXPRESSION = {
429 // computation expressions:
430 scope: 'computation-expression',
431 // BUG: might conflict with record deconstruction. e.g. let f { Name = name } = name // will highlight f
432 match: /\b[_a-z]\w*(?=\s*\{)/
433 };
434
435 const PREPROCESSOR = {
436 // preprocessor directives and fsi commands:
437 begin: [
438 /^\s*/,
439 concat(/#/, either(...PREPROCESSOR_KEYWORDS)),
440 /\b/
441 ],
442 beginScope: { 2: 'meta' },
443 end: lookahead(/\s|$/)
444 };
445
446 // TODO: this definition is missing support for type suffixes and octal notation.
447 // BUG: range operator without any space is wrongly interpreted as a single number (e.g. 1..10 )
448 const NUMBER = {
449 variants: [
450 hljs.BINARY_NUMBER_MODE,
451 hljs.C_NUMBER_MODE
452 ]
453 };
454
455 // All the following string definitions are potentially multi-line.
456 // BUG: these definitions are missing support for byte strings (suffixed with B)
457
458 // "..."
459 const QUOTED_STRING = {
460 scope: 'string',
461 begin: /"/,
462 end: /"/,
463 contains: [
464 hljs.BACKSLASH_ESCAPE
465 ]
466 };
467 // @"..."
468 const VERBATIM_STRING = {
469 scope: 'string',
470 begin: /@"/,
471 end: /"/,
472 contains: [
473 {
474 match: /""/ // escaped "
475 },
476 hljs.BACKSLASH_ESCAPE
477 ]
478 };
479 // """..."""
480 const TRIPLE_QUOTED_STRING = {
481 scope: 'string',
482 begin: /"""/,
483 end: /"""/,
484 relevance: 2
485 };
486 const SUBST = {
487 scope: 'subst',
488 begin: /\{/,
489 end: /\}/,
490 keywords: ALL_KEYWORDS
491 };
492 // $"...{1+1}..."
493 const INTERPOLATED_STRING = {
494 scope: 'string',
495 begin: /\$"/,
496 end: /"/,
497 contains: [
498 {
499 match: /\{\{/ // escaped {
500 },
501 {
502 match: /\}\}/ // escaped }
503 },
504 hljs.BACKSLASH_ESCAPE,
505 SUBST
506 ]
507 };
508 // $@"...{1+1}..."
509 const INTERPOLATED_VERBATIM_STRING = {
510 scope: 'string',
511 begin: /(\$@|@\$)"/,
512 end: /"/,
513 contains: [
514 {
515 match: /\{\{/ // escaped {
516 },
517 {
518 match: /\}\}/ // escaped }
519 },
520 {
521 match: /""/
522 },
523 hljs.BACKSLASH_ESCAPE,
524 SUBST
525 ]
526 };
527 // $"""...{1+1}..."""
528 const INTERPOLATED_TRIPLE_QUOTED_STRING = {
529 scope: 'string',
530 begin: /\$"""/,
531 end: /"""/,
532 contains: [
533 {
534 match: /\{\{/ // escaped {
535 },
536 {
537 match: /\}\}/ // escaped }
538 },
539 SUBST
540 ],
541 relevance: 2
542 };
543 // '.'
544 const CHAR_LITERAL = {
545 scope: 'string',
546 match: concat(
547 /'/,
548 either(
549 /[^\\']/, // either a single non escaped char...
550 /\\(?:.|\d{3}|x[a-fA-F\d]{2}|u[a-fA-F\d]{4}|U[a-fA-F\d]{8})/ // ...or an escape sequence
551 ),
552 /'/
553 )
554 };
555 // F# allows a lot of things inside string placeholders.
556 // Things that don't currently seem allowed by the compiler: types definition, attributes usage.
557 // (Strictly speaking, some of the followings are only allowed inside triple quoted interpolated strings...)
558 SUBST.contains = [
559 INTERPOLATED_VERBATIM_STRING,
560 INTERPOLATED_STRING,
561 VERBATIM_STRING,
562 QUOTED_STRING,
563 CHAR_LITERAL,
564 BANG_KEYWORD_MODE,
565 COMMENT,
566 QUOTED_IDENTIFIER,
567 TYPE_ANNOTATION,
568 COMPUTATION_EXPRESSION,
569 PREPROCESSOR,
570 NUMBER,
571 GENERIC_TYPE_SYMBOL,
572 OPERATOR
573 ];
574 const STRING = {
575 variants: [
576 INTERPOLATED_TRIPLE_QUOTED_STRING,
577 INTERPOLATED_VERBATIM_STRING,
578 INTERPOLATED_STRING,
579 TRIPLE_QUOTED_STRING,
580 VERBATIM_STRING,
581 QUOTED_STRING,
582 CHAR_LITERAL
583 ]
584 };
585
586 return {
587 name: 'F#',
588 aliases: [
589 'fs',
590 'f#'
591 ],
592 keywords: ALL_KEYWORDS,
593 illegal: /\/\*/,
594 classNameAliases: {
595 'computation-expression': 'keyword'
596 },
597 contains: [
598 BANG_KEYWORD_MODE,
599 STRING,
600 COMMENT,
601 QUOTED_IDENTIFIER,
602 TYPE_DECLARATION,
603 {
604 // e.g. [<Attributes("")>] or [<``module``: MyCustomAttributeThatWorksOnModules>]
605 // or [<Sealed; NoEquality; NoComparison; CompiledName("FSharpAsync`1")>]
606 scope: 'meta',
607 begin: /\[</,
608 end: />\]/,
609 relevance: 2,
610 contains: [
611 QUOTED_IDENTIFIER,
612 // can contain any constant value
613 TRIPLE_QUOTED_STRING,
614 VERBATIM_STRING,
615 QUOTED_STRING,
616 CHAR_LITERAL,
617 NUMBER
618 ]
619 },
620 DISCRIMINATED_UNION_TYPE_ANNOTATION,
621 TYPE_ANNOTATION,
622 COMPUTATION_EXPRESSION,
623 PREPROCESSOR,
624 NUMBER,
625 GENERIC_TYPE_SYMBOL,
626 OPERATOR
627 ]
628 };
629 }
630
631 return fsharp;
632
633 })();
634 ;
635 export default hljsGrammar;