]> luflow.net public git repositories - flow-web.git/blob - static/highlight/languages/swift.js
Initial commit.
[flow-web.git] / static / highlight / languages / swift.js
1 /*! `swift` grammar compiled for Highlight.js 11.11.1 */
2 (function(){
3 var hljsGrammar = (function () {
4 'use strict';
5
6 /**
7 * @param {string} value
8 * @returns {RegExp}
9 * */
10
11 /**
12 * @param {RegExp | string } re
13 * @returns {string}
14 */
15 function source(re) {
16 if (!re) return null;
17 if (typeof re === "string") return re;
18
19 return re.source;
20 }
21
22 /**
23 * @param {RegExp | string } re
24 * @returns {string}
25 */
26 function lookahead(re) {
27 return concat('(?=', re, ')');
28 }
29
30 /**
31 * @param {...(RegExp | string) } args
32 * @returns {string}
33 */
34 function concat(...args) {
35 const joined = args.map((x) => source(x)).join("");
36 return joined;
37 }
38
39 /**
40 * @param { Array<string | RegExp | Object> } args
41 * @returns {object}
42 */
43 function stripOptionsFromArgs(args) {
44 const opts = args[args.length - 1];
45
46 if (typeof opts === 'object' && opts.constructor === Object) {
47 args.splice(args.length - 1, 1);
48 return opts;
49 } else {
50 return {};
51 }
52 }
53
54 /** @typedef { {capture?: boolean} } RegexEitherOptions */
55
56 /**
57 * Any of the passed expresssions may match
58 *
59 * Creates a huge this | this | that | that match
60 * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args
61 * @returns {string}
62 */
63 function either(...args) {
64 /** @type { object & {capture?: boolean} } */
65 const opts = stripOptionsFromArgs(args);
66 const joined = '('
67 + (opts.capture ? "" : "?:")
68 + args.map((x) => source(x)).join("|") + ")";
69 return joined;
70 }
71
72 const keywordWrapper = keyword => concat(
73 /\b/,
74 keyword,
75 /\w$/.test(keyword) ? /\b/ : /\B/
76 );
77
78 // Keywords that require a leading dot.
79 const dotKeywords = [
80 'Protocol', // contextual
81 'Type' // contextual
82 ].map(keywordWrapper);
83
84 // Keywords that may have a leading dot.
85 const optionalDotKeywords = [
86 'init',
87 'self'
88 ].map(keywordWrapper);
89
90 // should register as keyword, not type
91 const keywordTypes = [
92 'Any',
93 'Self'
94 ];
95
96 // Regular keywords and literals.
97 const keywords = [
98 // strings below will be fed into the regular `keywords` engine while regex
99 // will result in additional modes being created to scan for those keywords to
100 // avoid conflicts with other rules
101 'actor',
102 'any', // contextual
103 'associatedtype',
104 'async',
105 'await',
106 /as\?/, // operator
107 /as!/, // operator
108 'as', // operator
109 'borrowing', // contextual
110 'break',
111 'case',
112 'catch',
113 'class',
114 'consume', // contextual
115 'consuming', // contextual
116 'continue',
117 'convenience', // contextual
118 'copy', // contextual
119 'default',
120 'defer',
121 'deinit',
122 'didSet', // contextual
123 'distributed',
124 'do',
125 'dynamic', // contextual
126 'each',
127 'else',
128 'enum',
129 'extension',
130 'fallthrough',
131 /fileprivate\(set\)/,
132 'fileprivate',
133 'final', // contextual
134 'for',
135 'func',
136 'get', // contextual
137 'guard',
138 'if',
139 'import',
140 'indirect', // contextual
141 'infix', // contextual
142 /init\?/,
143 /init!/,
144 'inout',
145 /internal\(set\)/,
146 'internal',
147 'in',
148 'is', // operator
149 'isolated', // contextual
150 'nonisolated', // contextual
151 'lazy', // contextual
152 'let',
153 'macro',
154 'mutating', // contextual
155 'nonmutating', // contextual
156 /open\(set\)/, // contextual
157 'open', // contextual
158 'operator',
159 'optional', // contextual
160 'override', // contextual
161 'package',
162 'postfix', // contextual
163 'precedencegroup',
164 'prefix', // contextual
165 /private\(set\)/,
166 'private',
167 'protocol',
168 /public\(set\)/,
169 'public',
170 'repeat',
171 'required', // contextual
172 'rethrows',
173 'return',
174 'set', // contextual
175 'some', // contextual
176 'static',
177 'struct',
178 'subscript',
179 'super',
180 'switch',
181 'throws',
182 'throw',
183 /try\?/, // operator
184 /try!/, // operator
185 'try', // operator
186 'typealias',
187 /unowned\(safe\)/, // contextual
188 /unowned\(unsafe\)/, // contextual
189 'unowned', // contextual
190 'var',
191 'weak', // contextual
192 'where',
193 'while',
194 'willSet' // contextual
195 ];
196
197 // NOTE: Contextual keywords are reserved only in specific contexts.
198 // Ideally, these should be matched using modes to avoid false positives.
199
200 // Literals.
201 const literals = [
202 'false',
203 'nil',
204 'true'
205 ];
206
207 // Keywords used in precedence groups.
208 const precedencegroupKeywords = [
209 'assignment',
210 'associativity',
211 'higherThan',
212 'left',
213 'lowerThan',
214 'none',
215 'right'
216 ];
217
218 // Keywords that start with a number sign (#).
219 // #(un)available is handled separately.
220 const numberSignKeywords = [
221 '#colorLiteral',
222 '#column',
223 '#dsohandle',
224 '#else',
225 '#elseif',
226 '#endif',
227 '#error',
228 '#file',
229 '#fileID',
230 '#fileLiteral',
231 '#filePath',
232 '#function',
233 '#if',
234 '#imageLiteral',
235 '#keyPath',
236 '#line',
237 '#selector',
238 '#sourceLocation',
239 '#warning'
240 ];
241
242 // Global functions in the Standard Library.
243 const builtIns = [
244 'abs',
245 'all',
246 'any',
247 'assert',
248 'assertionFailure',
249 'debugPrint',
250 'dump',
251 'fatalError',
252 'getVaList',
253 'isKnownUniquelyReferenced',
254 'max',
255 'min',
256 'numericCast',
257 'pointwiseMax',
258 'pointwiseMin',
259 'precondition',
260 'preconditionFailure',
261 'print',
262 'readLine',
263 'repeatElement',
264 'sequence',
265 'stride',
266 'swap',
267 'swift_unboxFromSwiftValueWithType',
268 'transcode',
269 'type',
270 'unsafeBitCast',
271 'unsafeDowncast',
272 'withExtendedLifetime',
273 'withUnsafeMutablePointer',
274 'withUnsafePointer',
275 'withVaList',
276 'withoutActuallyEscaping',
277 'zip'
278 ];
279
280 // Valid first characters for operators.
281 const operatorHead = either(
282 /[/=\-+!*%<>&|^~?]/,
283 /[\u00A1-\u00A7]/,
284 /[\u00A9\u00AB]/,
285 /[\u00AC\u00AE]/,
286 /[\u00B0\u00B1]/,
287 /[\u00B6\u00BB\u00BF\u00D7\u00F7]/,
288 /[\u2016-\u2017]/,
289 /[\u2020-\u2027]/,
290 /[\u2030-\u203E]/,
291 /[\u2041-\u2053]/,
292 /[\u2055-\u205E]/,
293 /[\u2190-\u23FF]/,
294 /[\u2500-\u2775]/,
295 /[\u2794-\u2BFF]/,
296 /[\u2E00-\u2E7F]/,
297 /[\u3001-\u3003]/,
298 /[\u3008-\u3020]/,
299 /[\u3030]/
300 );
301
302 // Valid characters for operators.
303 const operatorCharacter = either(
304 operatorHead,
305 /[\u0300-\u036F]/,
306 /[\u1DC0-\u1DFF]/,
307 /[\u20D0-\u20FF]/,
308 /[\uFE00-\uFE0F]/,
309 /[\uFE20-\uFE2F]/
310 // TODO: The following characters are also allowed, but the regex isn't supported yet.
311 // /[\u{E0100}-\u{E01EF}]/u
312 );
313
314 // Valid operator.
315 const operator = concat(operatorHead, operatorCharacter, '*');
316
317 // Valid first characters for identifiers.
318 const identifierHead = either(
319 /[a-zA-Z_]/,
320 /[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,
321 /[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,
322 /[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,
323 /[\u1E00-\u1FFF]/,
324 /[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,
325 /[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,
326 /[\u2C00-\u2DFF\u2E80-\u2FFF]/,
327 /[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,
328 /[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,
329 /[\uFE47-\uFEFE\uFF00-\uFFFD]/ // Should be /[\uFE47-\uFFFD]/, but we have to exclude FEFF.
330 // The following characters are also allowed, but the regexes aren't supported yet.
331 // /[\u{10000}-\u{1FFFD}\u{20000-\u{2FFFD}\u{30000}-\u{3FFFD}\u{40000}-\u{4FFFD}]/u,
332 // /[\u{50000}-\u{5FFFD}\u{60000-\u{6FFFD}\u{70000}-\u{7FFFD}\u{80000}-\u{8FFFD}]/u,
333 // /[\u{90000}-\u{9FFFD}\u{A0000-\u{AFFFD}\u{B0000}-\u{BFFFD}\u{C0000}-\u{CFFFD}]/u,
334 // /[\u{D0000}-\u{DFFFD}\u{E0000-\u{EFFFD}]/u
335 );
336
337 // Valid characters for identifiers.
338 const identifierCharacter = either(
339 identifierHead,
340 /\d/,
341 /[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/
342 );
343
344 // Valid identifier.
345 const identifier = concat(identifierHead, identifierCharacter, '*');
346
347 // Valid type identifier.
348 const typeIdentifier = concat(/[A-Z]/, identifierCharacter, '*');
349
350 // Built-in attributes, which are highlighted as keywords.
351 // @available is handled separately.
352 // https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes
353 const keywordAttributes = [
354 'attached',
355 'autoclosure',
356 concat(/convention\(/, either('swift', 'block', 'c'), /\)/),
357 'discardableResult',
358 'dynamicCallable',
359 'dynamicMemberLookup',
360 'escaping',
361 'freestanding',
362 'frozen',
363 'GKInspectable',
364 'IBAction',
365 'IBDesignable',
366 'IBInspectable',
367 'IBOutlet',
368 'IBSegueAction',
369 'inlinable',
370 'main',
371 'nonobjc',
372 'NSApplicationMain',
373 'NSCopying',
374 'NSManaged',
375 concat(/objc\(/, identifier, /\)/),
376 'objc',
377 'objcMembers',
378 'propertyWrapper',
379 'requires_stored_property_inits',
380 'resultBuilder',
381 'Sendable',
382 'testable',
383 'UIApplicationMain',
384 'unchecked',
385 'unknown',
386 'usableFromInline',
387 'warn_unqualified_access'
388 ];
389
390 // Contextual keywords used in @available and #(un)available.
391 const availabilityKeywords = [
392 'iOS',
393 'iOSApplicationExtension',
394 'macOS',
395 'macOSApplicationExtension',
396 'macCatalyst',
397 'macCatalystApplicationExtension',
398 'watchOS',
399 'watchOSApplicationExtension',
400 'tvOS',
401 'tvOSApplicationExtension',
402 'swift'
403 ];
404
405 /*
406 Language: Swift
407 Description: Swift is a general-purpose programming language built using a modern approach to safety, performance, and software design patterns.
408 Author: Steven Van Impe <steven.vanimpe@icloud.com>
409 Contributors: Chris Eidhof <chris@eidhof.nl>, Nate Cook <natecook@gmail.com>, Alexander Lichter <manniL@gmx.net>, Richard Gibson <gibson042@github>
410 Website: https://swift.org
411 Category: common, system
412 */
413
414
415 /** @type LanguageFn */
416 function swift(hljs) {
417 const WHITESPACE = {
418 match: /\s+/,
419 relevance: 0
420 };
421 // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID411
422 const BLOCK_COMMENT = hljs.COMMENT(
423 '/\\*',
424 '\\*/',
425 { contains: [ 'self' ] }
426 );
427 const COMMENTS = [
428 hljs.C_LINE_COMMENT_MODE,
429 BLOCK_COMMENT
430 ];
431
432 // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID413
433 // https://docs.swift.org/swift-book/ReferenceManual/zzSummaryOfTheGrammar.html
434 const DOT_KEYWORD = {
435 match: [
436 /\./,
437 either(...dotKeywords, ...optionalDotKeywords)
438 ],
439 className: { 2: "keyword" }
440 };
441 const KEYWORD_GUARD = {
442 // Consume .keyword to prevent highlighting properties and methods as keywords.
443 match: concat(/\./, either(...keywords)),
444 relevance: 0
445 };
446 const PLAIN_KEYWORDS = keywords
447 .filter(kw => typeof kw === 'string')
448 .concat([ "_|0" ]); // seems common, so 0 relevance
449 const REGEX_KEYWORDS = keywords
450 .filter(kw => typeof kw !== 'string') // find regex
451 .concat(keywordTypes)
452 .map(keywordWrapper);
453 const KEYWORD = { variants: [
454 {
455 className: 'keyword',
456 match: either(...REGEX_KEYWORDS, ...optionalDotKeywords)
457 }
458 ] };
459 // find all the regular keywords
460 const KEYWORDS = {
461 $pattern: either(
462 /\b\w+/, // regular keywords
463 /#\w+/ // number keywords
464 ),
465 keyword: PLAIN_KEYWORDS
466 .concat(numberSignKeywords),
467 literal: literals
468 };
469 const KEYWORD_MODES = [
470 DOT_KEYWORD,
471 KEYWORD_GUARD,
472 KEYWORD
473 ];
474
475 // https://github.com/apple/swift/tree/main/stdlib/public/core
476 const BUILT_IN_GUARD = {
477 // Consume .built_in to prevent highlighting properties and methods.
478 match: concat(/\./, either(...builtIns)),
479 relevance: 0
480 };
481 const BUILT_IN = {
482 className: 'built_in',
483 match: concat(/\b/, either(...builtIns), /(?=\()/)
484 };
485 const BUILT_INS = [
486 BUILT_IN_GUARD,
487 BUILT_IN
488 ];
489
490 // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418
491 const OPERATOR_GUARD = {
492 // Prevent -> from being highlighting as an operator.
493 match: /->/,
494 relevance: 0
495 };
496 const OPERATOR = {
497 className: 'operator',
498 relevance: 0,
499 variants: [
500 { match: operator },
501 {
502 // dot-operator: only operators that start with a dot are allowed to use dots as
503 // characters (..., ...<, .*, etc). So there rule here is: a dot followed by one or more
504 // characters that may also include dots.
505 match: `\\.(\\.|${operatorCharacter})+` }
506 ]
507 };
508 const OPERATORS = [
509 OPERATOR_GUARD,
510 OPERATOR
511 ];
512
513 // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#grammar_numeric-literal
514 // TODO: Update for leading `-` after lookbehind is supported everywhere
515 const decimalDigits = '([0-9]_*)+';
516 const hexDigits = '([0-9a-fA-F]_*)+';
517 const NUMBER = {
518 className: 'number',
519 relevance: 0,
520 variants: [
521 // decimal floating-point-literal (subsumes decimal-literal)
522 { match: `\\b(${decimalDigits})(\\.(${decimalDigits}))?` + `([eE][+-]?(${decimalDigits}))?\\b` },
523 // hexadecimal floating-point-literal (subsumes hexadecimal-literal)
524 { match: `\\b0x(${hexDigits})(\\.(${hexDigits}))?` + `([pP][+-]?(${decimalDigits}))?\\b` },
525 // octal-literal
526 { match: /\b0o([0-7]_*)+\b/ },
527 // binary-literal
528 { match: /\b0b([01]_*)+\b/ }
529 ]
530 };
531
532 // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#grammar_string-literal
533 const ESCAPED_CHARACTER = (rawDelimiter = "") => ({
534 className: 'subst',
535 variants: [
536 { match: concat(/\\/, rawDelimiter, /[0\\tnr"']/) },
537 { match: concat(/\\/, rawDelimiter, /u\{[0-9a-fA-F]{1,8}\}/) }
538 ]
539 });
540 const ESCAPED_NEWLINE = (rawDelimiter = "") => ({
541 className: 'subst',
542 match: concat(/\\/, rawDelimiter, /[\t ]*(?:[\r\n]|\r\n)/)
543 });
544 const INTERPOLATION = (rawDelimiter = "") => ({
545 className: 'subst',
546 label: "interpol",
547 begin: concat(/\\/, rawDelimiter, /\(/),
548 end: /\)/
549 });
550 const MULTILINE_STRING = (rawDelimiter = "") => ({
551 begin: concat(rawDelimiter, /"""/),
552 end: concat(/"""/, rawDelimiter),
553 contains: [
554 ESCAPED_CHARACTER(rawDelimiter),
555 ESCAPED_NEWLINE(rawDelimiter),
556 INTERPOLATION(rawDelimiter)
557 ]
558 });
559 const SINGLE_LINE_STRING = (rawDelimiter = "") => ({
560 begin: concat(rawDelimiter, /"/),
561 end: concat(/"/, rawDelimiter),
562 contains: [
563 ESCAPED_CHARACTER(rawDelimiter),
564 INTERPOLATION(rawDelimiter)
565 ]
566 });
567 const STRING = {
568 className: 'string',
569 variants: [
570 MULTILINE_STRING(),
571 MULTILINE_STRING("#"),
572 MULTILINE_STRING("##"),
573 MULTILINE_STRING("###"),
574 SINGLE_LINE_STRING(),
575 SINGLE_LINE_STRING("#"),
576 SINGLE_LINE_STRING("##"),
577 SINGLE_LINE_STRING("###")
578 ]
579 };
580
581 const REGEXP_CONTENTS = [
582 hljs.BACKSLASH_ESCAPE,
583 {
584 begin: /\[/,
585 end: /\]/,
586 relevance: 0,
587 contains: [ hljs.BACKSLASH_ESCAPE ]
588 }
589 ];
590
591 const BARE_REGEXP_LITERAL = {
592 begin: /\/[^\s](?=[^/\n]*\/)/,
593 end: /\//,
594 contains: REGEXP_CONTENTS
595 };
596
597 const EXTENDED_REGEXP_LITERAL = (rawDelimiter) => {
598 const begin = concat(rawDelimiter, /\//);
599 const end = concat(/\//, rawDelimiter);
600 return {
601 begin,
602 end,
603 contains: [
604 ...REGEXP_CONTENTS,
605 {
606 scope: "comment",
607 begin: `#(?!.*${end})`,
608 end: /$/,
609 },
610 ],
611 };
612 };
613
614 // https://docs.swift.org/swift-book/documentation/the-swift-programming-language/lexicalstructure/#Regular-Expression-Literals
615 const REGEXP = {
616 scope: "regexp",
617 variants: [
618 EXTENDED_REGEXP_LITERAL('###'),
619 EXTENDED_REGEXP_LITERAL('##'),
620 EXTENDED_REGEXP_LITERAL('#'),
621 BARE_REGEXP_LITERAL
622 ]
623 };
624
625 // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID412
626 const QUOTED_IDENTIFIER = { match: concat(/`/, identifier, /`/) };
627 const IMPLICIT_PARAMETER = {
628 className: 'variable',
629 match: /\$\d+/
630 };
631 const PROPERTY_WRAPPER_PROJECTION = {
632 className: 'variable',
633 match: `\\$${identifierCharacter}+`
634 };
635 const IDENTIFIERS = [
636 QUOTED_IDENTIFIER,
637 IMPLICIT_PARAMETER,
638 PROPERTY_WRAPPER_PROJECTION
639 ];
640
641 // https://docs.swift.org/swift-book/ReferenceManual/Attributes.html
642 const AVAILABLE_ATTRIBUTE = {
643 match: /(@|#(un)?)available/,
644 scope: 'keyword',
645 starts: { contains: [
646 {
647 begin: /\(/,
648 end: /\)/,
649 keywords: availabilityKeywords,
650 contains: [
651 ...OPERATORS,
652 NUMBER,
653 STRING
654 ]
655 }
656 ] }
657 };
658
659 const KEYWORD_ATTRIBUTE = {
660 scope: 'keyword',
661 match: concat(/@/, either(...keywordAttributes), lookahead(either(/\(/, /\s+/))),
662 };
663
664 const USER_DEFINED_ATTRIBUTE = {
665 scope: 'meta',
666 match: concat(/@/, identifier)
667 };
668
669 const ATTRIBUTES = [
670 AVAILABLE_ATTRIBUTE,
671 KEYWORD_ATTRIBUTE,
672 USER_DEFINED_ATTRIBUTE
673 ];
674
675 // https://docs.swift.org/swift-book/ReferenceManual/Types.html
676 const TYPE = {
677 match: lookahead(/\b[A-Z]/),
678 relevance: 0,
679 contains: [
680 { // Common Apple frameworks, for relevance boost
681 className: 'type',
682 match: concat(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/, identifierCharacter, '+')
683 },
684 { // Type identifier
685 className: 'type',
686 match: typeIdentifier,
687 relevance: 0
688 },
689 { // Optional type
690 match: /[?!]+/,
691 relevance: 0
692 },
693 { // Variadic parameter
694 match: /\.\.\./,
695 relevance: 0
696 },
697 { // Protocol composition
698 match: concat(/\s+&\s+/, lookahead(typeIdentifier)),
699 relevance: 0
700 }
701 ]
702 };
703 const GENERIC_ARGUMENTS = {
704 begin: /</,
705 end: />/,
706 keywords: KEYWORDS,
707 contains: [
708 ...COMMENTS,
709 ...KEYWORD_MODES,
710 ...ATTRIBUTES,
711 OPERATOR_GUARD,
712 TYPE
713 ]
714 };
715 TYPE.contains.push(GENERIC_ARGUMENTS);
716
717 // https://docs.swift.org/swift-book/ReferenceManual/Expressions.html#ID552
718 // Prevents element names from being highlighted as keywords.
719 const TUPLE_ELEMENT_NAME = {
720 match: concat(identifier, /\s*:/),
721 keywords: "_|0",
722 relevance: 0
723 };
724 // Matches tuples as well as the parameter list of a function type.
725 const TUPLE = {
726 begin: /\(/,
727 end: /\)/,
728 relevance: 0,
729 keywords: KEYWORDS,
730 contains: [
731 'self',
732 TUPLE_ELEMENT_NAME,
733 ...COMMENTS,
734 REGEXP,
735 ...KEYWORD_MODES,
736 ...BUILT_INS,
737 ...OPERATORS,
738 NUMBER,
739 STRING,
740 ...IDENTIFIERS,
741 ...ATTRIBUTES,
742 TYPE
743 ]
744 };
745
746 const GENERIC_PARAMETERS = {
747 begin: /</,
748 end: />/,
749 keywords: 'repeat each',
750 contains: [
751 ...COMMENTS,
752 TYPE
753 ]
754 };
755 const FUNCTION_PARAMETER_NAME = {
756 begin: either(
757 lookahead(concat(identifier, /\s*:/)),
758 lookahead(concat(identifier, /\s+/, identifier, /\s*:/))
759 ),
760 end: /:/,
761 relevance: 0,
762 contains: [
763 {
764 className: 'keyword',
765 match: /\b_\b/
766 },
767 {
768 className: 'params',
769 match: identifier
770 }
771 ]
772 };
773 const FUNCTION_PARAMETERS = {
774 begin: /\(/,
775 end: /\)/,
776 keywords: KEYWORDS,
777 contains: [
778 FUNCTION_PARAMETER_NAME,
779 ...COMMENTS,
780 ...KEYWORD_MODES,
781 ...OPERATORS,
782 NUMBER,
783 STRING,
784 ...ATTRIBUTES,
785 TYPE,
786 TUPLE
787 ],
788 endsParent: true,
789 illegal: /["']/
790 };
791 // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID362
792 // https://docs.swift.org/swift-book/documentation/the-swift-programming-language/declarations/#Macro-Declaration
793 const FUNCTION_OR_MACRO = {
794 match: [
795 /(func|macro)/,
796 /\s+/,
797 either(QUOTED_IDENTIFIER.match, identifier, operator)
798 ],
799 className: {
800 1: "keyword",
801 3: "title.function"
802 },
803 contains: [
804 GENERIC_PARAMETERS,
805 FUNCTION_PARAMETERS,
806 WHITESPACE
807 ],
808 illegal: [
809 /\[/,
810 /%/
811 ]
812 };
813
814 // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID375
815 // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID379
816 const INIT_SUBSCRIPT = {
817 match: [
818 /\b(?:subscript|init[?!]?)/,
819 /\s*(?=[<(])/,
820 ],
821 className: { 1: "keyword" },
822 contains: [
823 GENERIC_PARAMETERS,
824 FUNCTION_PARAMETERS,
825 WHITESPACE
826 ],
827 illegal: /\[|%/
828 };
829 // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID380
830 const OPERATOR_DECLARATION = {
831 match: [
832 /operator/,
833 /\s+/,
834 operator
835 ],
836 className: {
837 1: "keyword",
838 3: "title"
839 }
840 };
841
842 // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID550
843 const PRECEDENCEGROUP = {
844 begin: [
845 /precedencegroup/,
846 /\s+/,
847 typeIdentifier
848 ],
849 className: {
850 1: "keyword",
851 3: "title"
852 },
853 contains: [ TYPE ],
854 keywords: [
855 ...precedencegroupKeywords,
856 ...literals
857 ],
858 end: /}/
859 };
860
861 const CLASS_FUNC_DECLARATION = {
862 match: [
863 /class\b/,
864 /\s+/,
865 /func\b/,
866 /\s+/,
867 /\b[A-Za-z_][A-Za-z0-9_]*\b/
868 ],
869 scope: {
870 1: "keyword",
871 3: "keyword",
872 5: "title.function"
873 }
874 };
875
876 const CLASS_VAR_DECLARATION = {
877 match: [
878 /class\b/,
879 /\s+/,
880 /var\b/,
881 ],
882 scope: {
883 1: "keyword",
884 3: "keyword"
885 }
886 };
887
888 const TYPE_DECLARATION = {
889 begin: [
890 /(struct|protocol|class|extension|enum|actor)/,
891 /\s+/,
892 identifier,
893 /\s*/,
894 ],
895 beginScope: {
896 1: "keyword",
897 3: "title.class"
898 },
899 keywords: KEYWORDS,
900 contains: [
901 GENERIC_PARAMETERS,
902 ...KEYWORD_MODES,
903 {
904 begin: /:/,
905 end: /\{/,
906 keywords: KEYWORDS,
907 contains: [
908 {
909 scope: "title.class.inherited",
910 match: typeIdentifier,
911 },
912 ...KEYWORD_MODES,
913 ],
914 relevance: 0,
915 },
916 ]
917 };
918
919 // Add supported submodes to string interpolation.
920 for (const variant of STRING.variants) {
921 const interpolation = variant.contains.find(mode => mode.label === "interpol");
922 // TODO: Interpolation can contain any expression, so there's room for improvement here.
923 interpolation.keywords = KEYWORDS;
924 const submodes = [
925 ...KEYWORD_MODES,
926 ...BUILT_INS,
927 ...OPERATORS,
928 NUMBER,
929 STRING,
930 ...IDENTIFIERS
931 ];
932 interpolation.contains = [
933 ...submodes,
934 {
935 begin: /\(/,
936 end: /\)/,
937 contains: [
938 'self',
939 ...submodes
940 ]
941 }
942 ];
943 }
944
945 return {
946 name: 'Swift',
947 keywords: KEYWORDS,
948 contains: [
949 ...COMMENTS,
950 FUNCTION_OR_MACRO,
951 INIT_SUBSCRIPT,
952 CLASS_FUNC_DECLARATION,
953 CLASS_VAR_DECLARATION,
954 TYPE_DECLARATION,
955 OPERATOR_DECLARATION,
956 PRECEDENCEGROUP,
957 {
958 beginKeywords: 'import',
959 end: /$/,
960 contains: [ ...COMMENTS ],
961 relevance: 0
962 },
963 REGEXP,
964 ...KEYWORD_MODES,
965 ...BUILT_INS,
966 ...OPERATORS,
967 NUMBER,
968 STRING,
969 ...IDENTIFIERS,
970 ...ATTRIBUTES,
971 TYPE,
972 TUPLE
973 ]
974 };
975 }
976
977 return swift;
978
979 })();
980
981 hljs.registerLanguage('swift', hljsGrammar);
982 })();