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