|
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,11 @@ 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 = if let parseMissingArguments, leftParen.presence == .missing { |
| 227 | + parseMissingArguments(&self) |
| 228 | + } else { |
| 229 | + parseArguments(&self) |
| 230 | + } |
217 | 231 | let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen) |
218 | 232 | return .attribute( |
219 | 233 | RawAttributeSyntax( |
@@ -255,6 +269,12 @@ extension Parser { |
255 | 269 | } |
256 | 270 |
|
257 | 271 | switch peek(isAtAnyIn: DeclarationAttributeWithSpecialSyntax.self) { |
| 272 | + case .abi: |
| 273 | + return parseAttribute(argumentMode: .required) { parser in |
| 274 | + return .abiArguments(parser.parseABIAttributeArguments()) |
| 275 | + } parseMissingArguments: { parser in |
| 276 | + return .abiArguments(parser.parseABIAttributeArguments(missing: true)) |
| 277 | + } |
258 | 278 | case .available, ._spi_available: |
259 | 279 | return parseAttribute(argumentMode: .required) { parser in |
260 | 280 | return .availability(parser.parseAvailabilityArgumentSpecList()) |
@@ -918,6 +938,75 @@ extension Parser { |
918 | 938 | } |
919 | 939 | } |
920 | 940 |
|
| 941 | +extension Parser { |
| 942 | + mutating func parseABIAttributeArguments(missing: Bool = false) -> RawABIAttributeArgumentsSyntax { |
| 943 | + let providerDecl: RawABIAttributeArgumentsSyntax.Provider |
| 944 | + if missing || at(.rightParen) { |
| 945 | + // There are two situations where the left paren might be missing: |
| 946 | + // 1. The user just forgot the paren: `@abi var x_abi: Int) var x: Int` |
| 947 | + // 2. The user forgot the whole argument list: `@abi var x: Int` |
| 948 | + // Normally, we would distinguish these by seeing if whatever comes after |
| 949 | + // the attribute parses as an argument. However, for @abi the argument is |
| 950 | + // a decl, so in #2, we would consume the decl the attribute is attached |
| 951 | + // to! This leads to a lousy diagnostic in that situation. |
| 952 | + // Avoid this problem by simply returning a missing decl immediately. |
| 953 | + // FIXME: Could we look ahead to find an unbalanced parenthesis? |
| 954 | + providerDecl = .unsupported( |
| 955 | + RawDeclSyntax( |
| 956 | + RawMissingDeclSyntax( |
| 957 | + attributes: self.emptyCollection(RawAttributeListSyntax.self), |
| 958 | + modifiers: self.emptyCollection(RawDeclModifierListSyntax.self), |
| 959 | + arena: arena |
| 960 | + ) |
| 961 | + ) |
| 962 | + ) |
| 963 | + } else { |
| 964 | + switch nextDeclarationKeyword() { |
| 965 | + case .group?: |
| 966 | + providerDecl = RawABIAttributeArgumentsSyntax.Provider(parseDeclarationGroupHeader())! |
| 967 | + |
| 968 | + case .simple?, .binding?, nil: |
| 969 | + providerDecl = RawABIAttributeArgumentsSyntax.Provider(parseDeclaration(in: .argumentList))! |
| 970 | + } |
| 971 | + } |
| 972 | + |
| 973 | + return RawABIAttributeArgumentsSyntax(provider: providerDecl, arena: arena) |
| 974 | + } |
| 975 | + |
| 976 | + mutating func nextDeclarationKeyword() -> DeclarationKeyword? { |
| 977 | + return self.withLookahead { subparser in |
| 978 | + // Consume attributes. |
| 979 | + var attributeProgress = LoopProgressCondition() |
| 980 | + while subparser.hasProgressed(&attributeProgress) && subparser.at(.atSign) { |
| 981 | + _ = subparser.consumeAttributeList() |
| 982 | + } |
| 983 | + |
| 984 | + // Consume modifiers. |
| 985 | + if subparser.currentToken.isLexerClassifiedKeyword || subparser.currentToken.rawTokenKind == .identifier { |
| 986 | + var modifierProgress = LoopProgressCondition() |
| 987 | + while let (modifierKind, handle) = subparser.at(anyIn: DeclarationModifier.self), |
| 988 | + subparser.hasProgressed(&modifierProgress) |
| 989 | + { |
| 990 | + if modifierKind == .class { |
| 991 | + // `class` is a modifier only if it's followed by an introducer or modifier. |
| 992 | + if subparser.peek(isAtAnyIn: DeclarationStart.self) == nil { |
| 993 | + break |
| 994 | + } |
| 995 | + } |
| 996 | + subparser.eat(handle) |
| 997 | + if subparser.at(.leftParen) && modifierKind.canHaveParenthesizedArgument { |
| 998 | + subparser.consumeAnyToken() |
| 999 | + subparser.consume(to: .rightParen) |
| 1000 | + } |
| 1001 | + } |
| 1002 | + } |
| 1003 | + |
| 1004 | + // Is the next thing a declaration introducer? |
| 1005 | + return subparser.at(anyIn: DeclarationKeyword.self)?.spec |
| 1006 | + } |
| 1007 | + } |
| 1008 | +} |
| 1009 | + |
921 | 1010 | extension Parser { |
922 | 1011 | mutating func parseBackDeployedAttributeArguments() -> RawBackDeployedAttributeArgumentsSyntax { |
923 | 1012 | let (unexpectedBeforeLabel, label) = self.expect(.keyword(.before)) |
|
0 commit comments