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 })();