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