|
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