diff --git a/CHANGES.md b/CHANGES.md index 0fcb2f78e2..9fe2ccdd5b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,8 +8,14 @@ Language improvements: - enh(cpp): Support C++ pack expansion in function arguments [Martin Dørum][] - enh(makefile): Add `make` as an alias (#2883) [tripleee][] -- fix(http) avoid recursive sublanguage and tighten rules (#2893) [Josh Goebel][] - enh(swift) Improved grammar for strings (#2819) [Steven Van Impe][] +- enh(swift) Grammar improvements (#2908) [Steven Van Impe][] + - New grammar for keywords and built-ins + - Added support for operator highlighting + - New grammar for attributes + - Added support for quoted identifiers, implicit parameters, and property wrapper projections + - Support for more complex expressions in string interpolation +- fix(http) avoid recursive sublanguage and tighten rules (#2893) [Josh Goebel][] - fix(asciidoc): Handle section titles level 5 (#2868) [Vaibhav Chanana][] Grammar improvements: diff --git a/src/languages/lib/kws_swift.js b/src/languages/lib/kws_swift.js new file mode 100644 index 0000000000..f06a7104dc --- /dev/null +++ b/src/languages/lib/kws_swift.js @@ -0,0 +1,307 @@ +import { + concat, + either +} from '../../lib/regex.js'; + +export const keywordWrapper = keyword => concat( + /\b/, + keyword, + /\w$/.test(keyword) ? /\b/ : /\B/ +); + +// Keywords that require a leading dot. +export const dotKeywords = [ + 'Protocol', // contextual + 'Type' // contextual +].map(keywordWrapper); + +// Keywords that may have a leading dot. +export const optionalDotKeywords = [ + 'init', + 'self' +].map(keywordWrapper); + +// should register as keyword, not type +export const keywordTypes = [ + 'Any', + 'Self' +]; + +// Regular keywords and literals. +export const keywords = [ + // strings below will be fed into the regular `keywords` engine while regex + // will result in additional modes being created to scan for those keywords to + // avoid conflicts with other rules + 'associatedtype', + /as\?/, // operator + /as!/, // operator + 'as', // operator + 'break', + 'case', + 'catch', + 'class', + 'continue', + 'convenience', // contextual + 'default', + 'defer', + 'deinit', + 'didSet', // contextual + 'do', + 'dynamic', // contextual + 'else', + 'enum', + 'extension', + 'fallthrough', + 'fileprivate(set)', + 'fileprivate', + 'final', // contextual + 'for', + 'func', + 'get', // contextual + 'guard', + 'if', + 'import', + 'indirect', // contextual + 'infix', // contextual + /init\?/, + /init!/, + 'inout', + 'internal(set)', + 'internal', + 'in', + 'is', // operator + 'lazy', // contextual + 'let', + 'mutating', // contextual + 'nonmutating', // contextual + 'open(set)', // contextual + 'open', // contextual + 'operator', + 'optional', // contextual + 'override', // contextual + 'postfix', // contextual + 'precedencegroup', + 'prefix', // contextual + 'private(set)', + 'private', + 'protocol', + 'public(set)', + 'public', + 'repeat', + 'required', // contextual + 'rethrows', + 'return', + 'set', // contextual + 'some', // contextual + 'static', + 'struct', + 'subscript', + 'super', + 'switch', + 'throws', + 'throw', + /try\?/, // operator + /try!/, // operator + 'try', // operator + 'typealias', + 'unowned(safe)', // contextual + 'unowned(unsafe)', // contextual + 'unowned', // contextual + 'var', + 'weak', // contextual + 'where', + 'while', + 'willSet' // contextual +]; + +// NOTE: Contextual keywords are reserved only in specific contexts. +// Ideally, these should be matched using modes to avoid false positives. + +// TODO: Create a PRECEDENCE_GROUP mode to match the remaining contextual keywords: +// assignment associativity higherThan left lowerThan none right +// These aren't included in the list because they result in mostly false positives. + +// Literals. +export const literals = [ + 'false', + 'nil', + 'true' +]; + +// Keywords that start with a number sign (#). +// #available is handled separately. +export const numberSignKeywords = [ + '#colorLiteral', + '#column', + '#dsohandle', + '#else', + '#elseif', + '#endif', + '#error', + '#file', + '#fileID', + '#fileLiteral', + '#filePath', + '#function', + '#if', + '#imageLiteral', + '#keyPath', + '#line', + '#selector', + '#sourceLocation', + '#warn_unqualified_access', + '#warning' +]; + +// Global functions in the Standard Library. +export const builtIns = [ + 'abs', + 'all', + 'any', + 'assert', + 'assertionFailure', + 'debugPrint', + 'dump', + 'fatalError', + 'getVaList', + 'isKnownUniquelyReferenced', + 'max', + 'min', + 'numericCast', + 'pointwiseMax', + 'pointwiseMin', + 'precondition', + 'preconditionFailure', + 'print', + 'readLine', + 'repeatElement', + 'sequence', + 'stride', + 'swap', + 'swift_unboxFromSwiftValueWithType', + 'transcode', + 'type', + 'unsafeBitCast', + 'unsafeDowncast', + 'withExtendedLifetime', + 'withUnsafeMutablePointer', + 'withUnsafePointer', + 'withVaList', + 'withoutActuallyEscaping', + 'zip' +]; + +// Valid first characters for operators. +export const operatorHead = either( + /[/=\-+!*%<>&|^~?]/, + /[\u00A1-\u00A7]/, + /[\u00A9\u00AB]/, + /[\u00AC\u00AE]/, + /[\u00B0\u00B1]/, + /[\u00B6\u00BB\u00BF\u00D7\u00F7]/, + /[\u2016-\u2017]/, + /[\u2020-\u2027]/, + /[\u2030-\u203E]/, + /[\u2041-\u2053]/, + /[\u2055-\u205E]/, + /[\u2190-\u23FF]/, + /[\u2500-\u2775]/, + /[\u2794-\u2BFF]/, + /[\u2E00-\u2E7F]/, + /[\u3001-\u3003]/, + /[\u3008-\u3020]/, + /[\u3030]/ +); + +// Valid characters for operators. +export const operatorCharacter = either( + operatorHead, + /[\u0300-\u036F]/, + /[\u1DC0-\u1DFF]/, + /[\u20D0-\u20FF]/, + /[\uFE00-\uFE0F]/, + /[\uFE20-\uFE2F]/ + // TODO: The following characters are also allowed, but the regex isn't supported yet. + // /[\u{E0100}-\u{E01EF}]/u +); + +// Valid operator. +export const operator = concat(operatorHead, operatorCharacter, '*'); + +// Valid first characters for identifiers. +export const identifierHead = either( + /[a-zA-Z_]/, + /[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/, + /[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/, + /[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/, + /[\u1E00-\u1FFF]/, + /[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/, + /[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/, + /[\u2C00-\u2DFF\u2E80-\u2FFF]/, + /[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/, + /[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/, + /[\uFE47-\uFFFD]/ + // The following characters are also allowed, but the regexes aren't supported yet. + // /[\u{10000}-\u{1FFFD}\u{20000-\u{2FFFD}\u{30000}-\u{3FFFD}\u{40000}-\u{4FFFD}]/u, + // /[\u{50000}-\u{5FFFD}\u{60000-\u{6FFFD}\u{70000}-\u{7FFFD}\u{80000}-\u{8FFFD}]/u, + // /[\u{90000}-\u{9FFFD}\u{A0000-\u{AFFFD}\u{B0000}-\u{BFFFD}\u{C0000}-\u{CFFFD}]/u, + // /[\u{D0000}-\u{DFFFD}\u{E0000-\u{EFFFD}]/u +); + +// Valid characters for identifiers. +export const identifierCharacter = either( + identifierHead, + /\d/, + /[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/ +); + +// Valid identifier. +export const identifier = concat(identifierHead, identifierCharacter, '*'); + +// Built-in attributes, which are highlighted as keywords. +// @available is handled separately. +export const keywordAttributes = [ + 'autoclosure', + concat(/convention\(/, either('swift', 'block', 'c'), /\)/), + 'discardableResult', + 'dynamicCallable', + 'dynamicMemberLookup', + 'escaping', + 'frozen', + 'GKInspectable', + 'IBAction', + 'IBDesignable', + 'IBInspectable', + 'IBOutlet', + 'IBSegueAction', + 'inlinable', + 'main', + 'nonobjc', + 'NSApplicationMain', + 'NSCopying', + 'NSManaged', + concat(/objc\(/, identifier, /\)/), + 'objc', + 'objcMembers', + 'propertyWrapper', + 'requires_stored_property_inits', + 'testable', + 'UIApplicationMain', + 'unknown', + 'usableFromInline' +]; + +// Contextual keywords used in @available and #available. +export const availabilityKeywords = [ + 'iOS', + 'iOSApplicationExtension', + 'macOS', + 'macOSApplicationExtension', + 'macCatalyst', + 'macCatalystApplicationExtension', + 'watchOS', + 'watchOSApplicationExtension', + 'tvOS', + 'tvOSApplicationExtension', + 'swift' +]; diff --git a/src/languages/swift.js b/src/languages/swift.js index f33c7b4283..84c9f12f92 100644 --- a/src/languages/swift.js +++ b/src/languages/swift.js @@ -1,96 +1,135 @@ /* Language: Swift Description: Swift is a general-purpose programming language built using a modern approach to safety, performance, and software design patterns. -Author: Chris Eidhof -Contributors: Nate Cook , Alexander Lichter , Steven Van Impe +Author: Steven Van Impe +Contributors: Chris Eidhof , Nate Cook , Alexander Lichter , Richard Gibson Website: https://swift.org Category: common, system */ -import { concat } from "../lib/regex.js"; +import * as Swift from './lib/kws_swift.js'; +import { + concat, + either, + lookahead +} from '../lib/regex.js'; /** @type LanguageFn */ export default function(hljs) { - const SWIFT_KEYWORDS = { - // override the pattern since the default of of /\w+/ is not sufficient to - // capture the keywords that start with the character "#" - $pattern: /[\w#]+/, - keyword: '#available #colorLiteral #column #else #elseif #endif #file ' + - '#fileLiteral #function #if #imageLiteral #line #selector #sourceLocation ' + - '_ __COLUMN__ __FILE__ __FUNCTION__ __LINE__ Any as as! as? associatedtype ' + - 'associativity break case catch class continue convenience default defer deinit didSet do ' + - 'dynamic dynamicType else enum extension fallthrough false fileprivate final for func ' + - 'get guard if import in indirect infix init inout internal is lazy left let ' + - 'mutating nil none nonmutating open operator optional override postfix precedence ' + - 'prefix private protocol Protocol public repeat required rethrows return ' + - 'right self Self set some static struct subscript super switch throw throws true ' + - 'try try! try? Type typealias unowned var weak where while willSet', - literal: 'true false nil', - built_in: 'abs advance alignof alignofValue anyGenerator assert assertionFailure ' + - 'bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC ' + - 'bridgeToObjectiveCUnconditional c compactMap contains count countElements countLeadingZeros ' + - 'debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords ' + - 'enumerate equal fatalError filter find getBridgedObjectiveCType getVaList ' + - 'indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC ' + - 'isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare ' + - 'map max maxElement min minElement numericCast overlaps partition posix ' + - 'precondition preconditionFailure print println quickSort readLine reduce reflect ' + - 'reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split ' + - 'startsWith stride strideof strideofValue swap toString transcode ' + - 'underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap ' + - 'unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer ' + - 'withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers ' + - 'withUnsafePointer withUnsafePointers withVaList zip' - }; + // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID413 + // https://docs.swift.org/swift-book/ReferenceManual/zzSummaryOfTheGrammar.html + const DOT_KEYWORD = { + className: 'keyword', + begin: concat(/\./, lookahead(either(...Swift.dotKeywords, ...Swift.optionalDotKeywords))), + end: either(...Swift.dotKeywords, ...Swift.optionalDotKeywords), + excludeBegin: true + }; + const KEYWORD_GUARD = { + // Consume .keyword to prevent highlighting properties and methods as keywords. + begin: concat(/\./, either(...Swift.keywords)), + relevance: 0 + }; + const PLAIN_KEYWORDS = Swift.keywords + .filter(kw => typeof kw === 'string') + .concat([ "_|0" ]); // seems common, so 0 relevance + const REGEX_KEYWORDS = Swift.keywords + .filter(kw => typeof kw !== 'string') // find regex + .concat(Swift.keywordTypes) + .map(Swift.keywordWrapper); + const KEYWORD = { + variants: [ + { + className: 'keyword', + begin: either(...REGEX_KEYWORDS, ...Swift.optionalDotKeywords) + } + ] + }; + // find all the regular keywords + const KEYWORDS = { + $pattern: either( + /\b\w+(\(\w+\))?/, // kw or kw(arg) + /#\w+/ // number keywords + ), + keyword: PLAIN_KEYWORDS + .concat(Swift.numberSignKeywords) + .join(" "), + literal: Swift.literals.join(" ") + }; + const KEYWORD_MODES = [ + DOT_KEYWORD, + KEYWORD_GUARD, + KEYWORD + ]; - const TYPE = { - className: 'type', - begin: '\\b[A-Z][\\w\u00C0-\u02B8\']*', + // https://github.com/apple/swift/tree/main/stdlib/public/core + const BUILT_IN_GUARD = { + // Consume .built_in to prevent highlighting properties and methods. + begin: concat(/\./, either(...Swift.builtIns)), relevance: 0 }; - // slightly more special to swift - const OPTIONAL_USING_TYPE = { - className: 'type', - begin: '\\b[A-Z][\\w\u00C0-\u02B8\']*[!?]' + const BUILT_IN = { + className: 'built_in', + begin: concat(/\b/, either(...Swift.builtIns), /(?=\()/) + }; + const BUILT_INS = [ + BUILT_IN_GUARD, + BUILT_IN + ]; + + // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418 + const OPERATOR = { + className: 'operator', + relevance: 0, + variants: [ + { + begin: Swift.operator + }, + { + // dot-operator: only operators that start with a dot are allowed to use dots as + // characters (..., ...<, .*, etc). So there rule here is: a dot followed by one or more + // characters that may also include dots. + begin: `\\.(\\.|${Swift.operatorCharacter})+` + } + ] }; - const BLOCK_COMMENT = hljs.COMMENT( - '/\\*', - '\\*/', - { - contains: ['self'] - } - ); // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#grammar_numeric-literal // TODO: Update for leading `-` after lookbehind is supported everywhere const decimalDigits = '([0-9]_*)+'; const hexDigits = '([0-9a-fA-F]_*)+'; const NUMBER = { - className: 'number', - relevance: 0, - variants: [ - // decimal floating-point-literal (subsumes decimal-literal) - { begin: `\\b(${decimalDigits})(\\.(${decimalDigits}))?` + - `([eE][+-]?(${decimalDigits}))?\\b` }, - - // hexadecimal floating-point-literal (subsumes hexadecimal-literal) - { begin: `\\b0x(${hexDigits})(\\.(${hexDigits}))?` + - `([pP][+-]?(${decimalDigits}))?\\b` }, - - // octal-literal - { begin: /\b0o([0-7]_*)+\b/ }, - - // binary-literal - { begin: /\b0b([01]_*)+\b/ }, - ] + className: 'number', + relevance: 0, + variants: [ + // decimal floating-point-literal (subsumes decimal-literal) + { + begin: `\\b(${decimalDigits})(\\.(${decimalDigits}))?` + `([eE][+-]?(${decimalDigits}))?\\b` + }, + // hexadecimal floating-point-literal (subsumes hexadecimal-literal) + { + begin: `\\b0x(${hexDigits})(\\.(${hexDigits}))?` + `([pP][+-]?(${decimalDigits}))?\\b` + }, + // octal-literal + { + begin: /\b0o([0-7]_*)+\b/ + }, + // binary-literal + { + begin: /\b0b([01]_*)+\b/ + } + ] }; // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#grammar_string-literal const ESCAPED_CHARACTER = (rawDelimiter = "") => ({ className: 'subst', variants: [ - { begin: concat(/\\/, rawDelimiter, /[0\\tnr"']/) }, - { begin: concat(/\\/, rawDelimiter, /u\{[0-9a-fA-F]{1,8}\}/) } + { + begin: concat(/\\/, rawDelimiter, /[0\\tnr"']/) + }, + { + begin: concat(/\\/, rawDelimiter, /u\{[0-9a-fA-F]{1,8}\}/) + } ] }); const ESCAPED_NEWLINE = (rawDelimiter = "") => ({ @@ -106,12 +145,19 @@ export default function(hljs) { const MULTILINE_STRING = (rawDelimiter = "") => ({ begin: concat(rawDelimiter, /"""/), end: concat(/"""/, rawDelimiter), - contains: [ESCAPED_CHARACTER(rawDelimiter), ESCAPED_NEWLINE(rawDelimiter), INTERPOLATION(rawDelimiter)] + contains: [ + ESCAPED_CHARACTER(rawDelimiter), + ESCAPED_NEWLINE(rawDelimiter), + INTERPOLATION(rawDelimiter) + ] }); const SINGLE_LINE_STRING = (rawDelimiter = "") => ({ begin: concat(rawDelimiter, /"/), end: concat(/"/, rawDelimiter), - contains: [ESCAPED_CHARACTER(rawDelimiter), INTERPOLATION(rawDelimiter)] + contains: [ + ESCAPED_CHARACTER(rawDelimiter), + INTERPOLATION(rawDelimiter) + ] }); const STRING = { className: 'string', @@ -123,45 +169,140 @@ export default function(hljs) { SINGLE_LINE_STRING(), SINGLE_LINE_STRING("#"), SINGLE_LINE_STRING("##"), - SINGLE_LINE_STRING("###"), + SINGLE_LINE_STRING("###") ] }; + + // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID412 + const QUOTED_IDENTIFIER = { + begin: concat(/`/, Swift.identifier, /`/) + }; + const IMPLICIT_PARAMETER = { + className: 'variable', + begin: /\$\d+/ + }; + const PROPERTY_WRAPPER_PROJECTION = { + className: 'variable', + begin: `\\$${Swift.identifierCharacter}+` + }; + const IDENTIFIERS = [ + QUOTED_IDENTIFIER, + IMPLICIT_PARAMETER, + PROPERTY_WRAPPER_PROJECTION + ]; + + // https://docs.swift.org/swift-book/ReferenceManual/Attributes.html + const AVAILABLE_ATTRIBUTE = { + begin: /(@|#)available\(/, + end: /\)/, + keywords: { + $pattern: /[@#]?\w+/, + keyword: Swift.availabilityKeywords + .concat([ + "@available", + "#available" + ]) + .join(' ') + }, + contains: [ + OPERATOR, + NUMBER, + STRING + ] + }; + const KEYWORD_ATTRIBUTE = { + className: 'keyword', + begin: concat(/@/, either(...Swift.keywordAttributes)) + }; + const USER_DEFINED_ATTRIBUTE = { + className: 'meta', + begin: concat(/@/, Swift.identifier) + }; + const ATTRIBUTES = [ + AVAILABLE_ATTRIBUTE, + KEYWORD_ATTRIBUTE, + USER_DEFINED_ATTRIBUTE + ]; + + const TYPE = { + className: 'type', + begin: '\\b[A-Z][\\w\u00C0-\u02B8\']*', + relevance: 0 + }; + // slightly more special to swift + const OPTIONAL_USING_TYPE = { + className: 'type', + begin: '\\b[A-Z][\\w\u00C0-\u02B8\']*[!?]', + relevance: 0 + }; + const BLOCK_COMMENT = hljs.COMMENT( + '/\\*', + '\\*/', + { + contains: [ 'self' ] + } + ); + + // Add supported submodes to string interpolation. for (const variant of STRING.variants) { const interpolation = variant.contains.find(mode => mode.label === "interpol"); // TODO: Interpolation can contain any expression, so there's room for improvement here. - interpolation.contains = [STRING, NUMBER]; + interpolation.keywords = KEYWORDS; + const submodes = [ + ...KEYWORD_MODES, + ...BUILT_INS, + OPERATOR, + NUMBER, + STRING, + ...IDENTIFIERS + ]; + interpolation.contains = [ + ...submodes, + { + begin: /\(/, + end: /\)/, + contains: [ + 'self', + ...submodes + ] + } + ]; } return { name: 'Swift', - keywords: SWIFT_KEYWORDS, + keywords: KEYWORDS, contains: [ - STRING, hljs.C_LINE_COMMENT_MODE, BLOCK_COMMENT, - OPTIONAL_USING_TYPE, - TYPE, - NUMBER, { className: 'function', - beginKeywords: 'func', end: /\{/, excludeEnd: true, + beginKeywords: 'func', + end: /\{/, + excludeEnd: true, contains: [ hljs.inherit(hljs.TITLE_MODE, { begin: /[A-Za-z$_][0-9A-Za-z$_]*/ }), { - begin: // + begin: // }, { className: 'params', - begin: /\(/, end: /\)/, endsParent: true, - keywords: SWIFT_KEYWORDS, + begin: /\(/, + end: /\)/, + endsParent: true, + keywords: KEYWORDS, contains: [ 'self', + ...KEYWORD_MODES, NUMBER, STRING, hljs.C_BLOCK_COMMENT_MODE, - {begin: ':'} // relevance booster + { // relevance booster + begin: ':' + } ], illegal: /["']/ } @@ -171,28 +312,34 @@ export default function(hljs) { { className: 'class', beginKeywords: 'struct protocol class extension enum', - keywords: SWIFT_KEYWORDS, end: '\\{', excludeEnd: true, + keywords: KEYWORDS, contains: [ - hljs.inherit(hljs.TITLE_MODE, {begin: /[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}) + hljs.inherit(hljs.TITLE_MODE, { + begin: /[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/ + }), + ...KEYWORD_MODES ] }, { - className: 'meta', // @attributes - begin: '(@discardableResult|@warn_unused_result|@exported|@lazy|@noescape|' + - '@NSCopying|@NSManaged|@objc|@objcMembers|@convention|@required|' + - '@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|' + - '@infix|@prefix|@postfix|@autoclosure|@testable|@available|' + - '@nonobjc|@NSApplicationMain|@UIApplicationMain|@dynamicMemberLookup|' + - '@propertyWrapper|@main)\\b' - - }, - { - beginKeywords: 'import', end: /$/, - contains: [hljs.C_LINE_COMMENT_MODE, BLOCK_COMMENT], + beginKeywords: 'import', + end: /$/, + contains: [ + hljs.C_LINE_COMMENT_MODE, + BLOCK_COMMENT + ], relevance: 0 - } + }, + ...KEYWORD_MODES, + ...BUILT_INS, + OPERATOR, + NUMBER, + STRING, + ...IDENTIFIERS, + ...ATTRIBUTES, + OPTIONAL_USING_TYPE, + TYPE ] }; } diff --git a/test/markup/swift/attributes.expect.txt b/test/markup/swift/attributes.expect.txt new file mode 100644 index 0000000000..78936775ff --- /dev/null +++ b/test/markup/swift/attributes.expect.txt @@ -0,0 +1,9 @@ +@available(iOS 14, deprecated: "reason", *) +@convention(swift) +@objc +@objc(name) + +@propertyWrapper +@SomeWrapper(value: 1.0, other: "string", bool: false) + +@ notAnAttribute diff --git a/test/markup/swift/attributes.txt b/test/markup/swift/attributes.txt new file mode 100644 index 0000000000..3104b40cfa --- /dev/null +++ b/test/markup/swift/attributes.txt @@ -0,0 +1,9 @@ +@available(iOS 14, deprecated: "reason", *) +@convention(swift) +@objc +@objc(name) + +@propertyWrapper +@SomeWrapper(value: 1.0, other: "string", bool: false) + +@ notAnAttribute diff --git a/test/markup/swift/identifiers.expect.txt b/test/markup/swift/identifiers.expect.txt new file mode 100644 index 0000000000..a56b2fb051 --- /dev/null +++ b/test/markup/swift/identifiers.expect.txt @@ -0,0 +1,3 @@ +`func` +{ $0 + 1 } +value.$wrappedValue diff --git a/test/markup/swift/identifiers.txt b/test/markup/swift/identifiers.txt new file mode 100644 index 0000000000..be00a808cc --- /dev/null +++ b/test/markup/swift/identifiers.txt @@ -0,0 +1,3 @@ +`func` +{ $0 + 1 } +value.$wrappedValue diff --git a/test/markup/swift/keywords.expect.txt b/test/markup/swift/keywords.expect.txt new file mode 100644 index 0000000000..a7f03bca5e --- /dev/null +++ b/test/markup/swift/keywords.expect.txt @@ -0,0 +1,25 @@ +Sequence.Protocol Protocol +String.Type Type + +String.init init +String.self self + +Any Self +(_ name: String) +x as Int +x as? Double +x as! String +x is String +init?() init!() init +try? try! try +true false nil +fileprivate(set) internal(set) open(set) private(set) public(set) +unowned(safe) unowned(unsafe) + +#if +#error("Error") +#endif + +x.as(y) +x.for(y) +#notAKeyword diff --git a/test/markup/swift/keywords.txt b/test/markup/swift/keywords.txt new file mode 100644 index 0000000000..6b354c0db1 --- /dev/null +++ b/test/markup/swift/keywords.txt @@ -0,0 +1,25 @@ +Sequence.Protocol Protocol +String.Type Type + +String.init init +String.self self + +Any Self +(_ name: String) +x as Int +x as? Double +x as! String +x is String +init?() init!() init +try? try! try +true false nil +fileprivate(set) internal(set) open(set) private(set) public(set) +unowned(safe) unowned(unsafe) + +#if +#error("Error") +#endif + +x.as(y) +x.for(y) +#notAKeyword diff --git a/test/markup/swift/numbers.expect.txt b/test/markup/swift/numbers.expect.txt index 95eb9a2c2b..d022e50f9c 100644 --- a/test/markup/swift/numbers.expect.txt +++ b/test/markup/swift/numbers.expect.txt @@ -22,11 +22,11 @@ // expressions containing numeric literals -+0 -+-1 -2-3 --10.magnitude -fn(-5) ++0 ++-1 +2-3 +-10.magnitude +fn(-5) 0x2.p2 // expressions not containing numeric literals diff --git a/test/markup/swift/operators.expect.txt b/test/markup/swift/operators.expect.txt new file mode 100644 index 0000000000..99af8f6843 --- /dev/null +++ b/test/markup/swift/operators.expect.txt @@ -0,0 +1,98 @@ +!true +~x ++1 +-1 +..<1 +...1 +0... +a? +a! + +a << 1 +a<<1 +a >> 1 +a>>1 +a * 1 +a*1 +a / 1 +a/1 +a % 1 +a%1 +a &* 1 +a&*1 +a & b +a&b +a + 1 +a+1 +a - 1 +a-1 +a &+ 1 +a&+1 +a &- 1 +a&-1 +a | b +a|b +a ^ b +a^b +0 ..< 1 +0..<1 +0 ... 1 +0...1 +a ?? 1 +a??1 +a < 1 +a<1 +a <= 1 +a<=1 +a > 1 +a>1 +a >= 1 +a>=1 +a == 1 +a==1 +a != 1 +a!=1 +a === b +a===b +a !== b +a!==b +a ~= 1 +a~=1 +a .== b +a.==b +a .!= b +a.!=b +a .< b +a.<b +a .<= b +a.<=b +a .> b +a.>b +a .>= b +a.>=b +true && false +true&&false +true || false +true||false +a = 1 +a=1 +a *= 1 +a*=1 +a /= 1 +a/=1 +a %= 1 +a%=1 +a += 1 +a+=1 +a -= 1 +a-=1 +a <<= 1 +a<<=1 +a >>= 1 +a>>=1 +a &= b +a&=b +a |= b +a|=b +a ^= b +a^=b diff --git a/test/markup/swift/operators.txt b/test/markup/swift/operators.txt new file mode 100644 index 0000000000..b287b06e6b --- /dev/null +++ b/test/markup/swift/operators.txt @@ -0,0 +1,98 @@ +!true +~x ++1 +-1 +..<1 +...1 +0... +a? +a! + +a << 1 +a<<1 +a >> 1 +a>>1 +a * 1 +a*1 +a / 1 +a/1 +a % 1 +a%1 +a &* 1 +a&*1 +a & b +a&b +a + 1 +a+1 +a - 1 +a-1 +a &+ 1 +a&+1 +a &- 1 +a&-1 +a | b +a|b +a ^ b +a^b +0 ..< 1 +0..<1 +0 ... 1 +0...1 +a ?? 1 +a??1 +a < 1 +a<1 +a <= 1 +a<=1 +a > 1 +a>1 +a >= 1 +a>=1 +a == 1 +a==1 +a != 1 +a!=1 +a === b +a===b +a !== b +a!==b +a ~= 1 +a~=1 +a .== b +a.==b +a .!= b +a.!=b +a .< b +a. b +a.>b +a .>= b +a.>=b +true && false +true&&false +true || false +true||false +a = 1 +a=1 +a *= 1 +a*=1 +a /= 1 +a/=1 +a %= 1 +a%=1 +a += 1 +a+=1 +a -= 1 +a-=1 +a <<= 1 +a<<=1 +a >>= 1 +a>>=1 +a &= b +a&=b +a |= b +a|=b +a ^= b +a^=b diff --git a/test/markup/swift/strings.expect.txt b/test/markup/swift/strings.expect.txt index 88e36b6c90..8de232baf3 100644 --- a/test/markup/swift/strings.expect.txt +++ b/test/markup/swift/strings.expect.txt @@ -53,16 +53,16 @@ escaped newline \### ###"interpolation \###("string") raw \##("string") raw \#("string") raw \("string")"### """ -interpolation \(x) +interpolation \($0 + 1) """ #""" -interpolation \#(123) -raw \(123) +interpolation \#(abs(x - 2) as Double) +raw \(abs(x - 2) as Double) """# ##""" -interpolation \##(1.23) -raw \#(1.23) -raw \(1.23) +interpolation \##(true) +raw \#(true) +raw \(true) """## ###""" interpolation \###("string") diff --git a/test/markup/swift/strings.txt b/test/markup/swift/strings.txt index 7960261b43..6b177636a1 100644 --- a/test/markup/swift/strings.txt +++ b/test/markup/swift/strings.txt @@ -53,16 +53,16 @@ same line ###"interpolation \###("string") raw \##("string") raw \#("string") raw \("string")"### """ -interpolation \(x) +interpolation \($0 + 1) """ #""" -interpolation \#(123) -raw \(123) +interpolation \#(abs(x - 2) as Double) +raw \(abs(x - 2) as Double) """# ##""" -interpolation \##(1.23) -raw \#(1.23) -raw \(1.23) +interpolation \##(true) +raw \#(true) +raw \(true) """## ###""" interpolation \###("string") diff --git a/test/markup/swift/swiftui.expect.txt b/test/markup/swift/swiftui.expect.txt index 0d9fae6261..3b55db4dc3 100644 --- a/test/markup/swift/swiftui.expect.txt +++ b/test/markup/swift/swiftui.expect.txt @@ -1,4 +1,4 @@ -@main +@main struct MyApp: App { var body: some Scene { WindowGroup {