1 /*! `fsharp` grammar compiled for Highlight.js 11.11.1 */
3 var hljsGrammar
= (function () {
7 * @param {string} value
10 function escape(value
) {
11 return new RegExp(value
.replace(/[-/\\^$*+?.()|[\]{}]/g
, '\\$&'), 'm');
15 * @param {RegExp | string } re
20 if (typeof re
=== "string") return re
;
26 * @param {RegExp | string } re
29 function lookahead(re
) {
30 return concat('(?=', re
, ')');
34 * @param {...(RegExp | string) } args
37 function concat(...args
) {
38 const joined
= args
.map((x
) => source(x
)).join("");
43 * @param { Array<string | RegExp | Object> } args
46 function stripOptionsFromArgs(args
) {
47 const opts
= args
[args
.length
- 1];
49 if (typeof opts
=== 'object' && opts
.constructor === Object
) {
50 args
.splice(args
.length
- 1, 1);
57 /** @typedef { {capture?: boolean} } RegexEitherOptions */
60 * Any of the passed expresssions may match
62 * Creates a huge this | this | that | that match
63 * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args
66 function either(...args
) {
67 /** @type { object & {capture?: boolean} } */
68 const opts
= stripOptionsFromArgs(args
);
70 + (opts
.capture
? "" : "?:")
71 + args
.map((x
) => source(x
)).join("|") + ")";
77 Author: Jonas Follesø <jonas@follesoe.no>
78 Contributors: Troy Kershaw <hello@troykershaw.com>, Henrik Feldt <henrik@haf.se>, Melvyn Laïly <melvyn.laily@gmail.com>
79 Website: https://docs.microsoft.com/en-us/dotnet/fsharp/
84 /** @type LanguageFn */
85 function fsharp(hljs
) {
105 // "false", // literal
126 // "not", // built_in
127 // "null", // literal
140 // "true", // literal
153 const BANG_KEYWORD_MODE
= {
154 // monad builder keywords (matches before non-bang keywords)
156 match: /\b(yield|return|let|do|match|use)!/
159 const PREPROCESSOR_KEYWORDS
= [
189 const SPECIAL_IDENTIFIERS
= [
191 "__SOURCE_DIRECTORY__",
195 // Since it's possible to re-bind/shadow names (e.g. let char = 'c'),
196 // these builtin types should only be matched when a type name is expected.
197 const KNOWN_TYPES
= [
223 // other native types or lowercase aliases
236 // other important FSharp types
241 // Somewhat arbitrary list of builtin functions and values.
242 // Most of them are declared in Microsoft.FSharp.Core
243 // I tried to stay relevant by adding only the most idiomatic
244 // and most used symbols that are not already declared as types.
281 const ALL_KEYWORDS
= {
285 'variable.constant': SPECIAL_IDENTIFIERS
288 // (* potentially multi-line Meta Language style comment *)
290 hljs
.COMMENT(/\(\*(?!\))/, /\*\)/, {
293 // Either a multi-line (* Meta Language style comment *) or a single line // C style comment.
297 hljs
.C_LINE_COMMENT_MODE
,
301 // Most identifiers can contain apostrophes
302 const IDENTIFIER_RE
= /[a-zA-Z_](\w|')*/;
304 const QUOTED_IDENTIFIER
= {
310 // 'a or ^a where a can be a ``quoted identifier``
311 const BEGIN_GENERIC_TYPE_SYMBOL_RE
= /\B('|\^)/;
312 const GENERIC_TYPE_SYMBOL
= {
315 // the type name is a quoted identifier:
316 { match: concat(BEGIN_GENERIC_TYPE_SYMBOL_RE
, /``.*?``/) },
317 // the type name is a normal identifier (we don't use IDENTIFIER_RE because there cannot be another apostrophe here):
318 { match: concat(BEGIN_GENERIC_TYPE_SYMBOL_RE
, hljs
.UNDERSCORE_IDENT_RE
) }
323 const makeOperatorMode = function({ includeEqual
}) {
324 // List or symbolic operator characters from the FSharp Spec 4.1, minus the dot, and with `?` added, used for nullable operators.
325 let allOperatorChars
;
327 allOperatorChars
= "!%&*+-/<=>@^|~?";
329 allOperatorChars
= "!%&*+-/<>@^|~?";
330 const OPERATOR_CHARS
= Array
.from(allOperatorChars
);
331 const OPERATOR_CHAR_RE
= concat('[', ...OPERATOR_CHARS
.map(escape
), ']');
332 // 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.
333 const OPERATOR_CHAR_OR_DOT_RE
= either(OPERATOR_CHAR_RE
, /\./);
334 // When a dot is present, it must be followed by another operator char:
335 const OPERATOR_FIRST_CHAR_OF_MULTIPLE_RE
= concat(OPERATOR_CHAR_OR_DOT_RE
, lookahead(OPERATOR_CHAR_OR_DOT_RE
));
336 const SYMBOLIC_OPERATOR_RE
= either(
337 concat(OPERATOR_FIRST_CHAR_OF_MULTIPLE_RE
, OPERATOR_CHAR_OR_DOT_RE
, '*'), // Matches at least 2 chars operators
338 concat(OPERATOR_CHAR_RE
, '+'), // Matches at least one char operators
343 // symbolic operators:
344 SYMBOLIC_OPERATOR_RE
,
345 // other symbolic keywords:
346 // Type casting and conversion operators:
350 /:=/, // Reference cell assignment
352 /\$/), // A single $ can be used as an operator
357 const OPERATOR
= makeOperatorMode({ includeEqual: true });
358 // This variant is used when matching '=' should end a parent mode:
359 const OPERATOR_WITHOUT_EQUAL
= makeOperatorMode({ includeEqual: false });
361 const makeTypeAnnotationMode = function(prefix
, prefixScope
) {
363 begin: concat( // a type annotation is a
364 prefix
, // should be a colon or the 'of' keyword
365 lookahead( // that has to be followed by
367 /\s*/, // optional space
368 either( // then either of:
370 /'/, // generic type name
371 /\^/, // generic type name
372 /#/, // flexible type name
373 /``/, // quoted type name
374 /\(/, // parens type expression
375 /{\|/, // anonymous type annotation
377 beginScope: prefixScope,
378 // BUG: because ending with \n is necessary for some cases, multi-line type annotations are not properly supported.
379 // Examples where \n is required at the end:
380 // - abstract member definitions in classes: abstract Property : int * string
381 // - return type annotations: let f f' = f
' () : returnTypeAnnotation
382 // - record fields definitions: { A : int \n B : string }
388 // we need the known types, and we need the type constraint keywords and literals. e.g.: when 'a : null
389 keywords: hljs
.inherit(ALL_KEYWORDS
, { type: KNOWN_TYPES
}),
393 hljs
.inherit(QUOTED_IDENTIFIER
, { scope: null }), // match to avoid strange patterns inside that may break the parsing
394 OPERATOR_WITHOUT_EQUAL
399 const TYPE_ANNOTATION
= makeTypeAnnotationMode(/:/, 'operator');
400 const DISCRIMINATED_UNION_TYPE_ANNOTATION
= makeTypeAnnotationMode(/\bof\b/, 'keyword');
402 // type MyType<'a> = ...
403 const TYPE_DECLARATION
= {
405 /(^|\s+)/, // prevents matching the following: `match s.stype with`
414 end: lookahead(/\(|=|$/),
415 keywords: ALL_KEYWORDS
, // match keywords in type constraints. e.g.: when 'a : null
418 hljs
.inherit(QUOTED_IDENTIFIER
, { scope: null }), // match to avoid strange patterns inside that may break the parsing
421 // For visual consistency, highlight type brackets as operators.
425 TYPE_ANNOTATION
// generic types can have constraints, which are type annotations. e.g. type MyType<'T when 'T : delegate<obj * string>> =
429 const COMPUTATION_EXPRESSION
= {
430 // computation expressions:
431 scope: 'computation-expression',
432 // BUG: might conflict with record deconstruction. e.g. let f { Name = name } = name // will highlight f
433 match: /\b[_a-z]\w*(?=\s*\{)/
436 const PREPROCESSOR
= {
437 // preprocessor directives and fsi commands:
440 concat(/#/, either(...PREPROCESSOR_KEYWORDS
)),
443 beginScope: { 2: 'meta' },
444 end: lookahead(/\s|$/)
447 // TODO: this definition is missing support for type suffixes and octal notation.
448 // BUG: range operator without any space is wrongly interpreted as a single number (e.g. 1..10 )
451 hljs
.BINARY_NUMBER_MODE
,
456 // All the following string definitions are potentially multi-line.
457 // BUG: these definitions are missing support for byte strings (suffixed with B)
460 const QUOTED_STRING
= {
465 hljs
.BACKSLASH_ESCAPE
469 const VERBATIM_STRING
= {
475 match: /""/ // escaped "
477 hljs
.BACKSLASH_ESCAPE
481 const TRIPLE_QUOTED_STRING
= {
491 keywords: ALL_KEYWORDS
494 const INTERPOLATED_STRING
= {
500 match: /\{\{/ // escaped {
503 match: /\}\}/ // escaped }
505 hljs.BACKSLASH_ESCAPE,
510 const INTERPOLATED_VERBATIM_STRING = {
516 match: /\{\{/ // escaped {
519 match: /\}\}/ // escaped }
524 hljs.BACKSLASH_ESCAPE,
528 // $"""...{1+1}..."""
529 const INTERPOLATED_TRIPLE_QUOTED_STRING = {
535 match: /\{\{/ // escaped {
538 match: /\}\}/ // escaped }
545 const CHAR_LITERAL
= {
550 /[^\\']/, // either a single non escaped char...
551 /\\(?:.|\d{3}|x[a-fA-F\d]{2}|u[a-fA-F\d]{4}|U[a-fA-F\d]{8})/ // ...or an escape sequence
556 // F# allows a lot of things inside string placeholders.
557 // Things that don't currently seem allowed by the
compiler: types definition
, attributes usage
.
558 // (Strictly speaking, some of the followings are only allowed inside triple quoted interpolated strings...)
560 INTERPOLATED_VERBATIM_STRING
,
569 COMPUTATION_EXPRESSION
,
577 INTERPOLATED_TRIPLE_QUOTED_STRING
,
578 INTERPOLATED_VERBATIM_STRING
,
580 TRIPLE_QUOTED_STRING
,
593 keywords: ALL_KEYWORDS
,
596 'computation-expression': 'keyword'
605 // e.g. [<Attributes("")>] or [<``module``: MyCustomAttributeThatWorksOnModules>]
606 // or [<Sealed; NoEquality; NoComparison; CompiledName("FSharpAsync`1")>]
613 // can contain any constant value
614 TRIPLE_QUOTED_STRING
,
621 DISCRIMINATED_UNION_TYPE_ANNOTATION
,
623 COMPUTATION_EXPRESSION
,
636 hljs
.registerLanguage('fsharp', hljsGrammar
);