UNPKG

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