1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | function source(re) {
|
11 | if (!re) return null;
|
12 | if (typeof re === "string") return re;
|
13 |
|
14 | return re.source;
|
15 | }
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | function lookahead(re) {
|
22 | return concat('(?=', re, ')');
|
23 | }
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | function concat(...args) {
|
30 | const joined = args.map((x) => source(x)).join("");
|
31 | return joined;
|
32 | }
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | function 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 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | function either(...args) {
|
59 |
|
60 | const opts = stripOptionsFromArgs(args);
|
61 | const joined = '('
|
62 | + (opts.capture ? "" : "?:")
|
63 | + args.map((x) => source(x)).join("|") + ")";
|
64 | return joined;
|
65 | }
|
66 |
|
67 | const keywordWrapper = keyword => concat(
|
68 | /\b/,
|
69 | keyword,
|
70 | /\w$/.test(keyword) ? /\b/ : /\B/
|
71 | );
|
72 |
|
73 |
|
74 | const dotKeywords = [
|
75 | 'Protocol',
|
76 | 'Type'
|
77 | ].map(keywordWrapper);
|
78 |
|
79 |
|
80 | const optionalDotKeywords = [
|
81 | 'init',
|
82 | 'self'
|
83 | ].map(keywordWrapper);
|
84 |
|
85 |
|
86 | const keywordTypes = [
|
87 | 'Any',
|
88 | 'Self'
|
89 | ];
|
90 |
|
91 |
|
92 | const keywords = [
|
93 |
|
94 |
|
95 |
|
96 | 'actor',
|
97 | 'associatedtype',
|
98 | 'async',
|
99 | 'await',
|
100 | /as\?/, // operator
|
101 | /as!/, // operator
|
102 | 'as',
|
103 | 'break',
|
104 | 'case',
|
105 | 'catch',
|
106 | 'class',
|
107 | 'continue',
|
108 | 'convenience',
|
109 | 'default',
|
110 | 'defer',
|
111 | 'deinit',
|
112 | 'didSet',
|
113 | 'do',
|
114 | 'dynamic',
|
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.
|
187 | const literals = [
|
188 | 'false',
|
189 | 'nil',
|
190 | 'true'
|
191 | ];
|
192 |
|
193 | // Keywords used in precedence groups.
|
194 | const 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.
|
206 | const 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.
|
230 | const 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.
|
268 | const 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.
|
290 | const 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 |
|
302 | const operator = concat(operatorHead, operatorCharacter, '*');
|
303 |
|
304 |
|
305 | const 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]/
|
317 |
|
318 |
|
319 |
|
320 |
|
321 |
|
322 | );
|
323 |
|
324 |
|
325 | const identifierCharacter = either(
|
326 | identifierHead,
|
327 | /\d/,
|
328 | /[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/
|
329 | );
|
330 |
|
331 |
|
332 | const identifier = concat(identifierHead, identifierCharacter, '*');
|
333 |
|
334 |
|
335 | const typeIdentifier = concat(/[A-Z]/, identifierCharacter, '*');
|
336 |
|
337 |
|
338 |
|
339 | const 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 |
|
372 | const 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 |
|
387 |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 |
|
394 |
|
395 |
|
396 | function swift(hljs) {
|
397 | const WHITESPACE = {
|
398 | match: /\s+/,
|
399 | relevance: 0
|
400 | };
|
401 |
|
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 |
|
413 |
|
414 | const DOT_KEYWORD = {
|
415 | match: [
|
416 | /\./,
|
417 | either(...dotKeywords, ...optionalDotKeywords)
|
418 | ],
|
419 | className: { 2: "keyword" }
|
420 | };
|
421 | const KEYWORD_GUARD = {
|
422 |
|
423 | match: concat(/\./, either(...keywords)),
|
424 | relevance: 0
|
425 | };
|
426 | const PLAIN_KEYWORDS = keywords
|
427 | .filter(kw => typeof kw === 'string')
|
428 | .concat([ "_|0" ]);
|
429 | const REGEX_KEYWORDS = keywords
|
430 | .filter(kw => typeof kw !== 'string')
|
431 | .concat(keywordTypes)
|
432 | .map(keywordWrapper);
|
433 | const KEYWORD = { variants: [
|
434 | {
|
435 | className: 'keyword',
|
436 | match: either(...REGEX_KEYWORDS, ...optionalDotKeywords)
|
437 | }
|
438 | ] };
|
439 |
|
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 |
|
456 | const BUILT_IN_GUARD = {
|
457 |
|
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 |
|
471 | const OPERATOR_GUARD = {
|
472 |
|
473 | match: /->/,
|
474 | relevance: 0
|
475 | };
|
476 | const OPERATOR = {
|
477 | className: 'operator',
|
478 | relevance: 0,
|
479 | variants: [
|
480 | { match: operator },
|
481 | {
|
482 |
|
483 |
|
484 |
|
485 | match: `\\.(\\.|${operatorCharacter})+` }
|
486 | ]
|
487 | };
|
488 | const OPERATORS = [
|
489 | OPERATOR_GUARD,
|
490 | OPERATOR
|
491 | ];
|
492 |
|
493 |
|
494 |
|
495 | const decimalDigits = '([0-9]_*)+';
|
496 | const hexDigits = '([0-9a-fA-F]_*)+';
|
497 | const NUMBER = {
|
498 | className: 'number',
|
499 | relevance: 0,
|
500 | variants: [
|
501 |
|
502 | { match: `\\b(${decimalDigits})(\\.(${decimalDigits}))?` + `([eE][+-]?(${decimalDigits}))?\\b` },
|
503 |
|
504 | { match: `\\b0x(${hexDigits})(\\.(${hexDigits}))?` + `([pP][+-]?(${decimalDigits}))?\\b` },
|
505 |
|
506 | { match: /\b0o([0-7]_*)+\b/ },
|
507 |
|
508 | { match: /\b0b([01]_*)+\b/ }
|
509 | ]
|
510 | };
|
511 |
|
512 |
|
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 |
|
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 |
|
858 | module.exports = swift;
|
859 |
|
\ | No newline at end of file |