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