UNPKG

9.45 kBJavaScriptView Raw
1/**
2 * @param {string} value
3 * @returns {RegExp}
4 * */
5
6/**
7 * @param {RegExp | string } re
8 * @returns {string}
9 */
10function source(re) {
11 if (!re) return null;
12 if (typeof re === "string") return re;
13
14 return re.source;
15}
16
17/**
18 * @param {RegExp | string } re
19 * @returns {string}
20 */
21function lookahead(re) {
22 return concat('(?=', re, ')');
23}
24
25/**
26 * @param {...(RegExp | string) } args
27 * @returns {string}
28 */
29function concat(...args) {
30 const joined = args.map((x) => source(x)).join("");
31 return joined;
32}
33
34/**
35 * @param { Array<string | RegExp | Object> } args
36 * @returns {object}
37 */
38function stripOptionsFromArgs(args) {
39 const opts = args[args.length - 1];
40
41 if (typeof opts === 'object' && opts.constructor === Object) {
42 args.splice(args.length - 1, 1);
43 return opts;
44 } else {
45 return {};
46 }
47}
48
49/**
50 * Any of the passed expresssions may match
51 *
52 * Creates a huge this | this | that | that match
53 * @param {(RegExp | string)[] } args
54 * @returns {string}
55 */
56function either(...args) {
57 /** @type { object & {capture?: boolean} } */
58 const opts = stripOptionsFromArgs(args);
59 const joined = '('
60 + (opts.capture ? "" : "?:")
61 + args.map((x) => source(x)).join("|") + ")";
62 return joined;
63}
64
65/*
66Language: F#
67Author: Jonas Follesø <jonas@follesoe.no>
68Contributors: Troy Kershaw <hello@troykershaw.com>, Henrik Feldt <henrik@haf.se>, Melvyn Laïly <melvyn.laily@gmail.com>
69Website: https://docs.microsoft.com/en-us/dotnet/fsharp/
70Category: functional
71*/
72
73/** @type LanguageFn */
74function fsharp(hljs) {
75 const KEYWORDS = [
76 "abstract",
77 "and",
78 "as",
79 "assert",
80 "base",
81 "begin",
82 "class",
83 "default",
84 "delegate",
85 "do",
86 "done",
87 "downcast",
88 "downto",
89 "elif",
90 "else",
91 "end",
92 "exception",
93 "extern",
94 // "false", // literal
95 "finally",
96 "fixed",
97 "for",
98 "fun",
99 "function",
100 "global",
101 "if",
102 "in",
103 "inherit",
104 "inline",
105 "interface",
106 "internal",
107 "lazy",
108 "let",
109 "match",
110 "member",
111 "module",
112 "mutable",
113 "namespace",
114 "new",
115 // "not", // built_in
116 // "null", // literal
117 "of",
118 "open",
119 "or",
120 "override",
121 "private",
122 "public",
123 "rec",
124 "return",
125 "static",
126 "struct",
127 "then",
128 "to",
129 // "true", // literal
130 "try",
131 "type",
132 "upcast",
133 "use",
134 "val",
135 "void",
136 "when",
137 "while",
138 "with",
139 "yield"
140 ];
141
142 const BANG_KEYWORD_MODE = {
143 // monad builder keywords (matches before non-bang keywords)
144 scope: 'keyword',
145 match: /\b(yield|return|let|do|match|use)!/
146 };
147
148 const PREPROCESSOR_KEYWORDS = [
149 "if",
150 "else",
151 "endif",
152 "line",
153 "nowarn",
154 "light",
155 "r",
156 "i",
157 "I",
158 "load",
159 "time",
160 "help",
161 "quit"
162 ];
163
164 const LITERALS = [
165 "true",
166 "false",
167 "null",
168 "Some",
169 "None",
170 "Ok",
171 "Error",
172 "infinity",
173 "infinityf",
174 "nan",
175 "nanf"
176 ];
177
178 const SPECIAL_IDENTIFIERS = [
179 "__LINE__",
180 "__SOURCE_DIRECTORY__",
181 "__SOURCE_FILE__"
182 ];
183
184 const TYPES = [
185 // basic types
186 "bool",
187 "byte",
188 "sbyte",
189 "int8",
190 "int16",
191 "int32",
192 "uint8",
193 "uint16",
194 "uint32",
195 "int",
196 "uint",
197 "int64",
198 "uint64",
199 "nativeint",
200 "unativeint",
201 "decimal",
202 "float",
203 "double",
204 "float32",
205 "single",
206 "char",
207 "string",
208 "unit",
209 "bigint",
210 // other native types or lowercase aliases
211 "option",
212 "voption",
213 "list",
214 "array",
215 "seq",
216 "byref",
217 "exn",
218 "inref",
219 "nativeptr",
220 "obj",
221 "outref",
222 "voidptr"
223 ];
224
225 const BUILTINS = [
226 // Somewhat arbitrary list of builtin functions and values.
227 // Most of them are declared in Microsoft.FSharp.Core
228 // I tried to stay relevant by adding only the most idiomatic
229 // and most used symbols that are not already declared as types.
230 "not",
231 "ref",
232 "raise",
233 "reraise",
234 "dict",
235 "readOnlyDict",
236 "set",
237 "enum",
238 "sizeof",
239 "typeof",
240 "typedefof",
241 "nameof",
242 "nullArg",
243 "invalidArg",
244 "invalidOp",
245 "id",
246 "fst",
247 "snd",
248 "ignore",
249 "lock",
250 "using",
251 "box",
252 "unbox",
253 "tryUnbox",
254 "printf",
255 "printfn",
256 "sprintf",
257 "eprintf",
258 "eprintfn",
259 "fprintf",
260 "fprintfn",
261 "failwith",
262 "failwithf"
263 ];
264
265 const ALL_KEYWORDS = {
266 type: TYPES,
267 keyword: KEYWORDS,
268 literal: LITERALS,
269 built_in: BUILTINS,
270 'variable.constant': SPECIAL_IDENTIFIERS
271 };
272
273 // (* potentially multi-line Meta Language style comment *)
274 const ML_COMMENT =
275 hljs.COMMENT(/\(\*(?!\))/, /\*\)/, {
276 contains: ["self"]
277 });
278 // Either a multi-line (* Meta Language style comment *) or a single line // C style comment.
279 const COMMENT = {
280 variants: [
281 ML_COMMENT,
282 hljs.C_LINE_COMMENT_MODE,
283 ]
284 };
285
286 // 'a or ^a
287 const GENERIC_TYPE_SYMBOL = {
288 match: concat(/('|\^)/, hljs.UNDERSCORE_IDENT_RE),
289 scope: 'symbol',
290 relevance: 0
291 };
292
293 const COMPUTATION_EXPRESSION = {
294 // computation expressions:
295 scope: 'computation-expression',
296 match: /\b[_a-z]\w*(?=\s*\{)/
297 };
298
299 const PREPROCESSOR = {
300 // preprocessor directives and fsi commands:
301 begin: [
302 /^\s*/,
303 concat(/#/, either(...PREPROCESSOR_KEYWORDS)),
304 /\b/
305 ],
306 beginScope: { 2: 'meta' },
307 end: lookahead(/\s|$/)
308 };
309
310 // TODO: this definition is missing support for type suffixes and octal notation.
311 // BUG: range operator without any space is wrongly interpreted as a single number (e.g. 1..10 )
312 const NUMBER = {
313 variants: [
314 hljs.BINARY_NUMBER_MODE,
315 hljs.C_NUMBER_MODE
316 ]
317 };
318
319 // All the following string definitions are potentially multi-line.
320 // BUG: these definitions are missing support for byte strings (suffixed with B)
321
322 // "..."
323 const QUOTED_STRING = {
324 scope: 'string',
325 begin: /"/,
326 end: /"/,
327 contains: [
328 hljs.BACKSLASH_ESCAPE
329 ]
330 };
331 // @"..."
332 const VERBATIM_STRING = {
333 scope: 'string',
334 begin: /@"/,
335 end: /"/,
336 contains: [
337 {
338 match: /""/ // escaped "
339 },
340 hljs.BACKSLASH_ESCAPE
341 ]
342 };
343 // """..."""
344 const TRIPLE_QUOTED_STRING = {
345 scope: 'string',
346 begin: /"""/,
347 end: /"""/,
348 relevance: 2
349 };
350 const SUBST = {
351 scope: 'subst',
352 begin: /\{/,
353 end: /\}/,
354 keywords: ALL_KEYWORDS
355 };
356 // $"...{1+1}..."
357 const INTERPOLATED_STRING = {
358 scope: 'string',
359 begin: /\$"/,
360 end: /"/,
361 contains: [
362 {
363 match: /\{\{/ // escaped {
364 },
365 {
366 match: /\}\}/ // escaped }
367 },
368 hljs.BACKSLASH_ESCAPE,
369 SUBST
370 ]
371 };
372 // $@"...{1+1}..."
373 const INTERPOLATED_VERBATIM_STRING = {
374 scope: 'string',
375 begin: /(\$@|@\$)"/,
376 end: /"/,
377 contains: [
378 {
379 match: /\{\{/ // escaped {
380 },
381 {
382 match: /\}\}/ // escaped }
383 },
384 {
385 match: /""/
386 },
387 hljs.BACKSLASH_ESCAPE,
388 SUBST
389 ]
390 };
391 // $"""...{1+1}..."""
392 const INTERPOLATED_TRIPLE_QUOTED_STRING = {
393 scope: 'string',
394 begin: /\$"""/,
395 end: /"""/,
396 contains: [
397 {
398 match: /\{\{/ // escaped {
399 },
400 {
401 match: /\}\}/ // escaped }
402 },
403 SUBST
404 ],
405 relevance: 2
406 };
407 // '.'
408 const CHAR_LITERAL = {
409 scope: 'string',
410 match: concat(
411 /'/,
412 either(
413 /[^\\']/, // either a single non escaped char...
414 /\\(?:.|\d{3}|x[a-fA-F\d]{2}|u[a-fA-F\d]{4}|U[a-fA-F\d]{8})/ // ...or an escape sequence
415 ),
416 /'/
417 )
418 };
419 // F# allows a lot of things inside string placeholders.
420 // Things that don't currently seem allowed by the compiler: types definition, attributes usage.
421 // (Strictly speaking, some of the followings are only allowed inside triple quoted interpolated strings...)
422 SUBST.contains = [
423 INTERPOLATED_VERBATIM_STRING,
424 INTERPOLATED_STRING,
425 VERBATIM_STRING,
426 QUOTED_STRING,
427 CHAR_LITERAL,
428 BANG_KEYWORD_MODE,
429 COMMENT,
430 COMPUTATION_EXPRESSION,
431 PREPROCESSOR,
432 NUMBER,
433 GENERIC_TYPE_SYMBOL
434 ];
435 const STRING = {
436 variants: [
437 INTERPOLATED_TRIPLE_QUOTED_STRING,
438 INTERPOLATED_VERBATIM_STRING,
439 INTERPOLATED_STRING,
440 TRIPLE_QUOTED_STRING,
441 VERBATIM_STRING,
442 QUOTED_STRING,
443 CHAR_LITERAL
444 ]
445 };
446
447 return {
448 name: 'F#',
449 aliases: [
450 'fs',
451 'f#'
452 ],
453 keywords: ALL_KEYWORDS,
454 illegal: /\/\*/,
455 classNameAliases: {
456 'computation-expression': 'keyword'
457 },
458 contains: [
459 BANG_KEYWORD_MODE,
460 STRING,
461 COMMENT,
462 {
463 // type MyType<'a> = ...
464 begin: [
465 /type/,
466 /\s+/,
467 hljs.UNDERSCORE_IDENT_RE
468 ],
469 beginScope: {
470 1: 'keyword',
471 3: 'title.class'
472 },
473 end: lookahead(/\(|=|$/),
474 contains: [
475 GENERIC_TYPE_SYMBOL
476 ]
477 },
478 {
479 // [<Attributes("")>]
480 scope: 'meta',
481 begin: /^\s*\[</,
482 excludeBegin: true,
483 end: lookahead(/>\]/),
484 relevance: 2,
485 contains: [
486 {
487 scope: 'string',
488 begin: /"/,
489 end: /"/
490 },
491 NUMBER
492 ]
493 },
494 COMPUTATION_EXPRESSION,
495 PREPROCESSOR,
496 NUMBER,
497 GENERIC_TYPE_SYMBOL
498 ]
499 };
500}
501
502export { fsharp as default };