|
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