|
11 | 11 | //===----------------------------------------------------------------------===// |
12 | 12 |
|
13 | 13 | #if swift(>=6) |
14 | | -@_spi(RawSyntax) internal import SwiftSyntax |
| 14 | +@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) internal import SwiftSyntax |
15 | 15 | #else |
16 | | -@_spi(RawSyntax) import SwiftSyntax |
| 16 | +@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) import SwiftSyntax |
17 | 17 | #endif |
18 | 18 |
|
19 | 19 | extension Parser { |
@@ -58,6 +58,7 @@ extension Parser { |
58 | 58 | case _typeEraser |
59 | 59 | case _unavailableFromAsync |
60 | 60 | case `rethrows` |
| 61 | + case abi |
61 | 62 | case attached |
62 | 63 | case available |
63 | 64 | case backDeployed |
@@ -95,6 +96,7 @@ extension Parser { |
95 | 96 | case TokenSpec(._typeEraser): self = ._typeEraser |
96 | 97 | case TokenSpec(._unavailableFromAsync): self = ._unavailableFromAsync |
97 | 98 | case TokenSpec(.`rethrows`): self = .rethrows |
| 99 | + case TokenSpec(.abi) where experimentalFeatures.contains(.abiAttribute): self = .abi |
98 | 100 | case TokenSpec(.attached): self = .attached |
99 | 101 | case TokenSpec(.available): self = .available |
100 | 102 | case TokenSpec(.backDeployed): self = .backDeployed |
@@ -136,6 +138,7 @@ extension Parser { |
136 | 138 | case ._typeEraser: return .keyword(._typeEraser) |
137 | 139 | case ._unavailableFromAsync: return .keyword(._unavailableFromAsync) |
138 | 140 | case .`rethrows`: return .keyword(.rethrows) |
| 141 | + case .abi: return .keyword(.abi) |
139 | 142 | case .attached: return .keyword(.attached) |
140 | 143 | case .available: return .keyword(.available) |
141 | 144 | case .backDeployed: return .keyword(.backDeployed) |
@@ -176,9 +179,16 @@ extension Parser { |
176 | 179 | case noArgument |
177 | 180 | } |
178 | 181 |
|
| 182 | + /// Parse the argument of an attribute, if it has one. |
| 183 | + /// |
| 184 | + /// - Parameters: |
| 185 | + /// - argumentMode: Indicates whether the attribute must, may, or may not have an argument. |
| 186 | + /// - parseArguments: Called to parse the argument list. If there is an opening parenthesis, it will have already been consumed. |
| 187 | + /// - parseMissingArguments: If provided, called instead of `parseArgument` when an argument list was required but no opening parenthesis was present. |
179 | 188 | mutating func parseAttribute( |
180 | 189 | argumentMode: AttributeArgumentMode, |
181 | | - parseArguments: (inout Parser) -> RawAttributeSyntax.Arguments |
| 190 | + parseArguments: (inout Parser) -> RawAttributeSyntax.Arguments, |
| 191 | + parseMissingArguments: ((inout Parser) -> RawAttributeSyntax.Arguments)? = nil |
182 | 192 | ) -> RawAttributeListSyntax.Element { |
183 | 193 | var (unexpectedBeforeAtSign, atSign) = self.expect(.atSign) |
184 | 194 | if atSign.trailingTriviaByteLength > 0 || self.currentToken.leadingTriviaByteLength > 0 { |
@@ -213,7 +223,12 @@ extension Parser { |
213 | 223 | ) |
214 | 224 | leftParen = leftParen.tokenView.withTokenDiagnostic(tokenDiagnostic: diagnostic, arena: self.arena) |
215 | 225 | } |
216 | | - let argument = parseArguments(&self) |
| 226 | + let argument: RawAttributeSyntax.Arguments |
| 227 | + if let parseMissingArguments, leftParen.presence == .missing { |
| 228 | + argument = parseMissingArguments(&self) |
| 229 | + } else { |
| 230 | + argument = parseArguments(&self) |
| 231 | + } |
217 | 232 | let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen) |
218 | 233 | return .attribute( |
219 | 234 | RawAttributeSyntax( |
@@ -255,6 +270,12 @@ extension Parser { |
255 | 270 | } |
256 | 271 |
|
257 | 272 | switch peek(isAtAnyIn: DeclarationAttributeWithSpecialSyntax.self) { |
| 273 | + case .abi: |
| 274 | + return parseAttribute(argumentMode: .required) { parser in |
| 275 | + return .abiArguments(parser.parseABIAttributeArguments()) |
| 276 | + } parseMissingArguments: { parser in |
| 277 | + return .abiArguments(parser.parseABIAttributeArguments(missingLParen: true)) |
| 278 | + } |
258 | 279 | case .available, ._spi_available: |
259 | 280 | return parseAttribute(argumentMode: .required) { parser in |
260 | 281 | return .availability(parser.parseAvailabilityArgumentSpecList()) |
@@ -918,6 +939,52 @@ extension Parser { |
918 | 939 | } |
919 | 940 | } |
920 | 941 |
|
| 942 | +extension Parser { |
| 943 | + /// Parse the arguments inside an `@abi(...)` attribute. |
| 944 | + /// |
| 945 | + /// - Parameter missingLParen: `true` if the opening paren for the argument list was missing. |
| 946 | + mutating func parseABIAttributeArguments(missingLParen: Bool = false) -> RawABIAttributeArgumentsSyntax { |
| 947 | + func makeMissingProviderArguments(unexpectedBefore: [RawSyntax]) -> RawABIAttributeArgumentsSyntax { |
| 948 | + return RawABIAttributeArgumentsSyntax( |
| 949 | + provider: .missing( |
| 950 | + RawMissingDeclSyntax( |
| 951 | + unexpectedBefore.isEmpty ? nil : RawUnexpectedNodesSyntax(elements: unexpectedBefore, arena: self.arena), |
| 952 | + attributes: self.emptyCollection(RawAttributeListSyntax.self), |
| 953 | + modifiers: self.emptyCollection(RawDeclModifierListSyntax.self), |
| 954 | + placeholder: self.missingToken(.identifier, text: "<#declaration#>"), |
| 955 | + arena: arena |
| 956 | + ) |
| 957 | + ), |
| 958 | + arena: self.arena |
| 959 | + ) |
| 960 | + } |
| 961 | + |
| 962 | + // Consider the three kinds of mistakes we might see here: |
| 963 | + // |
| 964 | + // 1. The user forgot the argument: `@abi(<<here>>) var x: Int` |
| 965 | + // 2. The user forgot the left paren: `@abi<<here>> var x_abi: Int) var x: Int` |
| 966 | + // 3. The user forgot the whole argument list: `@abi<<here>> var x: Int` |
| 967 | + // |
| 968 | + // It's difficult to write code that recovers from both #2 and #3. The problem is that in both cases, what comes |
| 969 | + // next looks like a declaration, so a simple lookahead cannot distinguish between them--you'd have to parse all |
| 970 | + // the way to the closing paren. (And what if *that's* also missing?) |
| 971 | + // |
| 972 | + // In lieu of that, we judge that recovering gracefully from #3 is more important than #2 and therefore do not even |
| 973 | + // attempt to parse the argument unless we've seen a left paren. |
| 974 | + guard !missingLParen && !self.at(.rightParen) else { |
| 975 | + return makeMissingProviderArguments(unexpectedBefore: []) |
| 976 | + } |
| 977 | + |
| 978 | + let decl = parseDeclaration(in: .argumentList) |
| 979 | + |
| 980 | + guard let provider = RawABIAttributeArgumentsSyntax.Provider(decl) else { |
| 981 | + return makeMissingProviderArguments(unexpectedBefore: [decl.raw]) |
| 982 | + } |
| 983 | + |
| 984 | + return RawABIAttributeArgumentsSyntax(provider: provider, arena: self.arena) |
| 985 | + } |
| 986 | +} |
| 987 | + |
921 | 988 | extension Parser { |
922 | 989 | mutating func parseBackDeployedAttributeArguments() -> RawBackDeployedAttributeArgumentsSyntax { |
923 | 990 | let (unexpectedBeforeLabel, label) = self.expect(.keyword(.before)) |
|
0 commit comments