1 /*! `swift` grammar compiled for Highlight.js 11.11.1 */
3 var hljsGrammar
= (function () {
7 * @param {string} value
12 * @param {RegExp | string } re
17 if (typeof re
=== "string") return re
;
23 * @param {RegExp | string } re
26 function lookahead(re
) {
27 return concat('(?=', re
, ')');
31 * @param {...(RegExp | string) } args
34 function concat(...args
) {
35 const joined
= args
.map((x
) => source(x
)).join("");
40 * @param { Array<string | RegExp | Object> } args
43 function stripOptionsFromArgs(args
) {
44 const opts
= args
[args
.length
- 1];
46 if (typeof opts
=== 'object' && opts
.constructor === Object
) {
47 args
.splice(args
.length
- 1, 1);
54 /** @typedef { {capture?: boolean} } RegexEitherOptions */
57 * Any of the passed expresssions may match
59 * Creates a huge this | this | that | that match
60 * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args
63 function either(...args
) {
64 /** @type { object & {capture?: boolean} } */
65 const opts
= stripOptionsFromArgs(args
);
67 + (opts
.capture
? "" : "?:")
68 + args
.map((x
) => source(x
)).join("|") + ")";
72 const keywordWrapper
= keyword
=> concat(
75 /\w$/.test(keyword
) ? /\b/ : /\B/
78 // Keywords that require a leading dot.
80 'Protocol', // contextual
82 ].map(keywordWrapper
);
84 // Keywords that may have a leading dot.
85 const optionalDotKeywords
= [
88 ].map(keywordWrapper
);
90 // should register as keyword, not type
91 const keywordTypes
= [
96 // Regular keywords and literals.
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
109 'borrowing', // contextual
114 'consume', // contextual
115 'consuming', // contextual
117 'convenience', // contextual
118 'copy', // contextual
122 'didSet', // contextual
125 'dynamic', // contextual
131 /fileprivate\(set\)/,
133 'final', // contextual
140 'indirect', // contextual
141 'infix', // contextual
149 'isolated', // contextual
150 'nonisolated', // contextual
151 'lazy', // contextual
154 'mutating', // contextual
155 'nonmutating', // contextual
156 /open\(set\)/, // contextual
157 'open', // contextual
159 'optional', // contextual
160 'override', // contextual
162 'postfix', // contextual
164 'prefix', // contextual
171 'required', // contextual
175 'some', // contextual
187 /unowned\(safe\)/, // contextual
188 /unowned\(unsafe\)/, // contextual
189 'unowned', // contextual
191 'weak', // contextual
194 'willSet' // contextual
197 // NOTE: Contextual keywords are reserved only in specific contexts.
198 // Ideally, these should be matched using modes to avoid false positives.
207 // Keywords used in precedence groups.
208 const precedencegroupKeywords
= [
218 // Keywords that start with a number sign (#).
219 // #(un)available is handled separately.
220 const numberSignKeywords
= [
242 // Global functions in the Standard Library.
253 'isKnownUniquelyReferenced',
260 'preconditionFailure',
267 'swift_unboxFromSwiftValueWithType',
272 'withExtendedLifetime',
273 'withUnsafeMutablePointer',
276 'withoutActuallyEscaping',
280 // Valid first characters for operators.
281 const operatorHead
= either(
287 /[\u00B6\u00BB\u00BF\u00D7\u00F7]/,
302 // Valid characters for operators.
303 const operatorCharacter
= either(
310 // TODO: The following characters are also allowed, but the regex isn't supported yet.
311 // /[\u{E0100}-\u{E01EF}]/u
315 const operator
= concat(operatorHead
, operatorCharacter
, '*');
317 // Valid first characters for identifiers.
318 const identifierHead
= either(
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]/,
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
337 // Valid characters for identifiers.
338 const identifierCharacter
= either(
341 /[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/
345 const identifier
= concat(identifierHead
, identifierCharacter
, '*');
347 // Valid type identifier.
348 const typeIdentifier
= concat(/[A-Z]/, identifierCharacter
, '*');
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
= [
356 concat(/convention\(/, either('swift', 'block', 'c'), /\)/),
359 'dynamicMemberLookup',
375 concat(/objc\(/, identifier
, /\)/),
379 'requires_stored_property_inits',
387 'warn_unqualified_access'
390 // Contextual keywords used in @available and #(un)available.
391 const availabilityKeywords
= [
393 'iOSApplicationExtension',
395 'macOSApplicationExtension',
397 'macCatalystApplicationExtension',
399 'watchOSApplicationExtension',
401 'tvOSApplicationExtension',
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
415 /** @type LanguageFn */
416 function swift(hljs
) {
421 // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID411
422 const BLOCK_COMMENT
= hljs
.COMMENT(
425 { contains: [ 'self' ] }
428 hljs
.C_LINE_COMMENT_MODE
,
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
= {
437 either(...dotKeywords
, ...optionalDotKeywords
)
439 className: { 2: "keyword" }
441 const KEYWORD_GUARD
= {
442 // Consume .keyword to prevent highlighting properties and methods as keywords.
443 match: concat(/\./, either(...keywords
)),
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: [
455 className: 'keyword',
456 match: either(...REGEX_KEYWORDS
, ...optionalDotKeywords
)
459 // find all the regular keywords
462 /\b\w+/, // regular keywords
463 /#\w+/ // number keywords
465 keyword: PLAIN_KEYWORDS
466 .concat(numberSignKeywords
),
469 const KEYWORD_MODES
= [
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
)),
482 className: 'built_in',
483 match: concat(/\b/, either(...builtIns
), /(?=\()/)
490 // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418
491 const OPERATOR_GUARD
= {
492 // Prevent -> from being highlighting as an operator.
497 className: 'operator',
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})+` }
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]_*)+';
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` },
526 { match: /\b0o([0-7]_*)+\b/ },
528 { match: /\b0b([01]_*)+\b/ }
532 // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#grammar_string-literal
533 const ESCAPED_CHARACTER
= (rawDelimiter
= "") => ({
536 { match: concat(/\\/, rawDelimiter
, /[0\\tnr"']/) },
537 { match: concat(/\\/, rawDelimiter
, /u\{[0-9a-fA-F]{1,8}\}/) }
540 const ESCAPED_NEWLINE
= (rawDelimiter
= "") => ({
542 match: concat(/\\/, rawDelimiter
, /[\t ]*(?:[\r\n]|\r\n)/)
544 const INTERPOLATION
= (rawDelimiter
= "") => ({
547 begin: concat(/\\/, rawDelimiter
, /\(/),
550 const MULTILINE_STRING
= (rawDelimiter
= "") => ({
551 begin: concat(rawDelimiter
, /"""/),
552 end: concat(/"""/, rawDelimiter
),
554 ESCAPED_CHARACTER(rawDelimiter
),
555 ESCAPED_NEWLINE(rawDelimiter
),
556 INTERPOLATION(rawDelimiter
)
559 const SINGLE_LINE_STRING
= (rawDelimiter
= "") => ({
560 begin: concat(rawDelimiter
, /"/),
561 end: concat(/"/, rawDelimiter
),
563 ESCAPED_CHARACTER(rawDelimiter
),
564 INTERPOLATION(rawDelimiter
)
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("###")
581 const REGEXP_CONTENTS
= [
582 hljs
.BACKSLASH_ESCAPE
,
587 contains: [ hljs
.BACKSLASH_ESCAPE
]
591 const BARE_REGEXP_LITERAL
= {
592 begin: /\/[^\s](?=[^/\n]*\/)/,
594 contains: REGEXP_CONTENTS
597 const EXTENDED_REGEXP_LITERAL
= (rawDelimiter
) => {
598 const begin
= concat(rawDelimiter
, /\//);
599 const end
= concat(/\//, rawDelimiter
);
607 begin: `#(?!.*${end})`,
614 // https://docs.swift.org/swift-book/documentation/the-swift-programming-language/lexicalstructure/#Regular-Expression-Literals
618 EXTENDED_REGEXP_LITERAL('###'),
619 EXTENDED_REGEXP_LITERAL('##'),
620 EXTENDED_REGEXP_LITERAL('#'),
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',
631 const PROPERTY_WRAPPER_PROJECTION
= {
632 className: 'variable',
633 match: `\\$${identifierCharacter}+`
635 const IDENTIFIERS
= [
638 PROPERTY_WRAPPER_PROJECTION
641 // https://docs.swift.org/swift-book/ReferenceManual/Attributes.html
642 const AVAILABLE_ATTRIBUTE
= {
643 match: /(@|#(un)?)available/,
645 starts: { contains: [
649 keywords: availabilityKeywords
,
659 const KEYWORD_ATTRIBUTE
= {
661 match: concat(/@/, either(...keywordAttributes
), lookahead(either(/\(/, /\s+/))),
664 const USER_DEFINED_ATTRIBUTE
= {
666 match: concat(/@/, identifier
)
672 USER_DEFINED_ATTRIBUTE
675 // https://docs.swift.org/swift-book/ReferenceManual/Types.html
677 match: lookahead(/\b[A-Z]/),
680 { // Common Apple frameworks, for relevance boost
682 match: concat(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/, identifierCharacter
, '+')
686 match: typeIdentifier
,
693 { // Variadic parameter
697 { // Protocol composition
698 match: concat(/\s+&\s+/, lookahead(typeIdentifier
)),
703 const GENERIC_ARGUMENTS
= {
715 TYPE
.contains
.push(GENERIC_ARGUMENTS
);
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*:/),
724 // Matches tuples as well as the parameter list of a function type.
746 const GENERIC_PARAMETERS
= {
749 keywords: 'repeat each',
755 const FUNCTION_PARAMETER_NAME
= {
757 lookahead(concat(identifier
, /\s*:/)),
758 lookahead(concat(identifier
, /\s+/, identifier
, /\s*:/))
764 className: 'keyword',
773 const FUNCTION_PARAMETERS
= {
778 FUNCTION_PARAMETER_NAME
,
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
= {
797 either(QUOTED_IDENTIFIER
.match
, identifier
, operator
)
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
= {
818 /\b(?:subscript|init[?!]?)/,
821 className: { 1: "keyword" },
829 // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID380
830 const OPERATOR_DECLARATION
= {
842 // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID550
843 const PRECEDENCEGROUP
= {
855 ...precedencegroupKeywords
,
861 const CLASS_FUNC_DECLARATION
= {
867 /\b[A-Za-z_][A-Za-z0-9_]*\b/
876 const CLASS_VAR_DECLARATION
= {
888 const TYPE_DECLARATION
= {
890 /(struct|protocol|class|extension|enum|actor)/,
909 scope: "title.class.inherited",
910 match: typeIdentifier
,
919 // Add supported submodes to string interpolation.
920 for (const variant
of STRING
.variants
) {
921 const interpolation
= variant
.contains
.find(mode
=> mode
.label
=== "interpol");
922 // TODO: Interpolation can contain any expression, so there's room for improvement here.
923 interpolation
.keywords
= KEYWORDS
;
932 interpolation
.contains
= [
952 CLASS_FUNC_DECLARATION
,
953 CLASS_VAR_DECLARATION
,
955 OPERATOR_DECLARATION
,
958 beginKeywords: 'import',
960 contains: [ ...COMMENTS
],
981 hljs
.registerLanguage('swift', hljsGrammar
);