/ src / theme / languages / swift.js
swift.js
  1  /*! `swift` grammar compiled for Highlight.js 11.10.0 */
  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 TYPE_DECLARATION = {
862        begin: [
863          /(struct|protocol|class|extension|enum|actor)/,
864          /\s+/,
865          identifier,
866          /\s*/,
867        ],
868        beginScope: {
869          1: "keyword",
870          3: "title.class"
871        },
872        keywords: KEYWORDS,
873        contains: [
874          GENERIC_PARAMETERS,
875          ...KEYWORD_MODES,
876          {
877            begin: /:/,
878            end: /\{/,
879            keywords: KEYWORDS,
880            contains: [
881              {
882                scope: "title.class.inherited",
883                match: typeIdentifier,
884              },
885              ...KEYWORD_MODES,
886            ],
887            relevance: 0,
888          },
889        ]
890      };
891  
892      // Add supported submodes to string interpolation.
893      for (const variant of STRING.variants) {
894        const interpolation = variant.contains.find(mode => mode.label === "interpol");
895        // TODO: Interpolation can contain any expression, so there's room for improvement here.
896        interpolation.keywords = KEYWORDS;
897        const submodes = [
898          ...KEYWORD_MODES,
899          ...BUILT_INS,
900          ...OPERATORS,
901          NUMBER,
902          STRING,
903          ...IDENTIFIERS
904        ];
905        interpolation.contains = [
906          ...submodes,
907          {
908            begin: /\(/,
909            end: /\)/,
910            contains: [
911              'self',
912              ...submodes
913            ]
914          }
915        ];
916      }
917  
918      return {
919        name: 'Swift',
920        keywords: KEYWORDS,
921        contains: [
922          ...COMMENTS,
923          FUNCTION_OR_MACRO,
924          INIT_SUBSCRIPT,
925          TYPE_DECLARATION,
926          OPERATOR_DECLARATION,
927          PRECEDENCEGROUP,
928          {
929            beginKeywords: 'import',
930            end: /$/,
931            contains: [ ...COMMENTS ],
932            relevance: 0
933          },
934          REGEXP,
935          ...KEYWORD_MODES,
936          ...BUILT_INS,
937          ...OPERATORS,
938          NUMBER,
939          STRING,
940          ...IDENTIFIERS,
941          ...ATTRIBUTES,
942          TYPE,
943          TUPLE
944        ]
945      };
946    }
947  
948    return swift;
949  
950  })();
951  
952      hljs.registerLanguage('swift', hljsGrammar);
953    })();