Skip to content

Commit b743ff7

Browse files
committed
Add support for parsing ordinary (non-accessor) coroutines
1 parent b29349c commit b743ff7

36 files changed

Lines changed: 952 additions & 159 deletions

CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,11 @@ public let DECL_NODES: [Node] = [
11591159
documentation: "The effect indicators of the function, like `async` or `throws`",
11601160
isOptional: true
11611161
),
1162+
Child(
1163+
name: "yieldsClause",
1164+
kind: .node(kind: .yieldsClause),
1165+
isOptional: true
1166+
),
11621167
Child(
11631168
name: "returnClause",
11641169
kind: .node(kind: .returnClause),
@@ -2167,6 +2172,41 @@ public let DECL_NODES: [Node] = [
21672172
]
21682173
),
21692174

2175+
Node(
2176+
kind: .yieldsClause,
2177+
base: .syntax,
2178+
nameForDiagnostics: "yields clause",
2179+
children: [
2180+
Child(
2181+
name: "yieldsKeyword",
2182+
// .token(.identifier) here is a hack to not require SPI while compiling the generated syntax files
2183+
// as otherwise we're ending with `yieldsKeyword: TokenSyntax = .keyword(.yields)` with default argument
2184+
// being an SPI
2185+
kind: .token(choices: [.token(.identifier), .keyword(.yields)]),
2186+
documentation: "The `yields` keyword."
2187+
),
2188+
Child(
2189+
name: "leftParen",
2190+
kind: .token(choices: [.token(.leftParen)]),
2191+
documentation: "The '(' to open the yield type specification.",
2192+
isOptional: true
2193+
),
2194+
Child(
2195+
name: "type",
2196+
kind: .node(kind: .type),
2197+
nameForDiagnostics: "yield type",
2198+
documentation: "The yielded type.",
2199+
isOptional: true
2200+
),
2201+
Child(
2202+
name: "rightParen",
2203+
kind: .token(choices: [.token(.rightParen)]),
2204+
documentation: "The ')' to close the yield type specification.",
2205+
isOptional: true
2206+
),
2207+
],
2208+
),
2209+
21702210
Node(
21712211
kind: .returnClause,
21722212
base: .syntax,
@@ -2385,6 +2425,11 @@ public let DECL_NODES: [Node] = [
23852425
name: "parameterClause",
23862426
kind: .node(kind: .functionParameterClause)
23872427
),
2428+
Child(
2429+
name: "yieldsClause",
2430+
kind: .node(kind: .yieldsClause),
2431+
isOptional: true
2432+
),
23882433
Child(
23892434
name: "returnClause",
23902435
kind: .node(kind: .returnClause)

CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public enum ExperimentalFeature: String, CaseIterable {
2323
case oldOwnershipOperatorSpellings
2424
case defaultIsolationPerFile
2525
case borrowAndMutateAccessors
26+
case coroutineFunctions
2627

2728
/// The name of the feature as it is written in the compiler's `Features.def` file.
2829
public var featureName: String {
@@ -47,6 +48,8 @@ public enum ExperimentalFeature: String, CaseIterable {
4748
return "DefaultIsolationPerFile"
4849
case .borrowAndMutateAccessors:
4950
return "BorrowAndMutateAccessors"
51+
case .coroutineFunctions:
52+
return "CoroutineFunctions"
5053
}
5154
}
5255

@@ -73,6 +76,8 @@ public enum ExperimentalFeature: String, CaseIterable {
7376
return "set default actor isolation for a file"
7477
case .borrowAndMutateAccessors:
7578
return "borrow and mutate accessors"
79+
case .coroutineFunctions:
80+
return "functions as coroutines"
7681
}
7782
}
7883

CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,11 @@ public let EXPR_NODES: [Node] = [
631631
kind: .node(kind: .typeEffectSpecifiers),
632632
isOptional: true
633633
),
634+
Child(
635+
name: "yieldsClause",
636+
kind: .node(kind: .yieldsClause),
637+
isOptional: true
638+
),
634639
Child(
635640
name: "returnClause",
636641
kind: .node(kind: .returnClause),

CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ public enum Keyword: CaseIterable {
280280
case wrt
281281
case yield
282282
case yielding
283+
case `yields`
284+
case `yield_once`
283285

284286
public var spec: KeywordSpec {
285287
switch self {
@@ -701,6 +703,10 @@ public enum Keyword: CaseIterable {
701703
return KeywordSpec("yield")
702704
case .yielding:
703705
return KeywordSpec("yielding")
706+
case .yield_once:
707+
return KeywordSpec("yield_once", experimentalFeature: .coroutineFunctions)
708+
case .yields:
709+
return KeywordSpec("yields", experimentalFeature: .coroutineFunctions)
704710
}
705711
}
706712
}

CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ public enum SyntaxNodeKind: String, CaseIterable, IdentifierConvertible, TypeCon
316316
case whereClause
317317
case whileStmt
318318
case wildcardPattern
319+
case yieldsClause
319320
case yieldedExpression
320321
case yieldedExpressionList
321322
case yieldedExpressionsClause

CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ public let TYPE_NODES: [Node] = [
212212
kind: .node(kind: .typeEffectSpecifiers),
213213
isOptional: true
214214
),
215+
Child(
216+
name: "yieldsClause",
217+
kind: .node(kind: .yieldsClause),
218+
isOptional: true
219+
),
215220
Child(
216221
name: "returnClause",
217222
kind: .node(kind: .returnClause)

Sources/SwiftParser/Attributes.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ extension Parser {
8989
case objc
9090
case Sendable
9191
case transpose
92+
case `yield_once`
9293

9394
init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
9495
switch PrepareForKeywordMatch(lexeme) {
@@ -112,6 +113,7 @@ extension Parser {
112113
case TokenSpec(.objc): self = .objc
113114
case TokenSpec(.Sendable): self = .Sendable
114115
case TokenSpec(.transpose): self = .transpose
116+
case TokenSpec(.`yield_once`): self = .yield_once
115117
default:
116118
return nil
117119
}
@@ -139,6 +141,7 @@ extension Parser {
139141
case .objc: return .keyword(.objc)
140142
case .Sendable: return .keyword(.Sendable)
141143
case .transpose: return .keyword(.transpose)
144+
case .`yield_once`: return .keyword(.yield_once)
142145
}
143146
}
144147
}
@@ -347,6 +350,10 @@ extension Parser {
347350
return parseAttribute(argumentMode: .noArgument) { parser in
348351
preconditionFailure("Sendable has no argument")
349352
}
353+
case .yield_once:
354+
return parseAttribute(argumentMode: .noArgument) { parser in
355+
preconditionFailure("yield_once has no argument")
356+
}
350357
case nil:
351358
return parseAttribute(argumentMode: .customAttribute) { parser in
352359
let arguments = parser.parseArgumentListElements(
@@ -1139,7 +1146,8 @@ extension Parser.Lookahead {
11391146
TokenSpec(.rightParen),
11401147
TokenSpec(.rightBrace),
11411148
TokenSpec(.rightSquare),
1142-
TokenSpec(.rightAngle):
1149+
TokenSpec(.rightAngle),
1150+
TokenSpec(.yields):
11431151
return false
11441152
case _ where lookahead.at(.keyword(.async)):
11451153
return false

Sources/SwiftParser/Declarations.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,12 +1334,13 @@ extension Parser {
13341334
}
13351335

13361336
extension Parser {
1337-
/// If a `throws` keyword appears right in front of the `arrow`, it is returned as `misplacedThrowsKeyword` so it can be synthesized in front of the arrow.
1337+
/// If a `throws` keyword appears right behind of the `arrow`, it is returned as `misplacedThrowsKeyword` so it can be synthesized in front of the arrow.
13381338
mutating func parseFunctionReturnClause(
13391339
effectSpecifiers: inout (some RawMisplacedEffectSpecifiersTrait)?,
13401340
allowNamedOpaqueResultType: Bool
13411341
) -> RawReturnClauseSyntax {
13421342
let (unexpectedBeforeArrow, arrow) = self.expect(.arrow)
1343+
13431344
let unexpectedBeforeReturnType = self.parseMisplacedEffectSpecifiers(&effectSpecifiers)
13441345
let type: RawTypeSyntax
13451346
if allowNamedOpaqueResultType {
@@ -1429,7 +1430,7 @@ extension Parser {
14291430
parser.parseFunctionParameter()
14301431
}
14311432

1432-
var effectSpecifiers = self.parseFunctionEffectSpecifiers()
1433+
var (effectSpecifiers, yields) = self.parseFunctionEffectSpecifiers()
14331434

14341435
var returnClause: RawReturnClauseSyntax?
14351436

@@ -1443,10 +1444,10 @@ extension Parser {
14431444
} else {
14441445
returnClause = nil
14451446
}
1446-
14471447
return RawFunctionSignatureSyntax(
14481448
parameterClause: parameterClause,
14491449
effectSpecifiers: effectSpecifiers,
1450+
yieldsClause: yields,
14501451
returnClause: returnClause,
14511452
arena: self.arena
14521453
)
@@ -1509,6 +1510,7 @@ extension Parser {
15091510
RawUnexpectedNodesSyntax([unexpectedName], arena: self.arena),
15101511
genericParameterClause: genericParameterClause,
15111512
parameterClause: parameterClause,
1513+
yieldsClause: nil,
15121514
returnClause: returnClause,
15131515
genericWhereClause: genericWhereClause,
15141516
accessorBlock: accessor,

Sources/SwiftParser/Expressions.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ extension Parser {
363363
return nil
364364
}
365365
case (.arrow, _)?, (.throws, _)?:
366-
var effectSpecifiers = self.parseTypeEffectSpecifiers()
366+
var (effectSpecifiers, _) = self.parseTypeEffectSpecifiers()
367367

368368
let (unexpectedBeforeArrow, arrow) = self.expect(.arrow)
369369

@@ -2003,6 +2003,7 @@ extension Parser {
20032003

20042004
var parameterClause: RawClosureSignatureSyntax.ParameterClause?
20052005
var effectSpecifiers: RawTypeEffectSpecifiersSyntax?
2006+
var yields: RawYieldsClauseSyntax? = nil
20062007
var returnClause: RawReturnClauseSyntax? = nil
20072008
if !self.at(.keyword(.in)) {
20082009
// If the next token is ':', then it looks like the code contained a non-shorthand closure parameter with a type annotation.
@@ -2043,7 +2044,7 @@ extension Parser {
20432044
parameterClause = .simpleInput(RawClosureShorthandParameterListSyntax(elements: params, arena: self.arena))
20442045
}
20452046

2046-
effectSpecifiers = self.parseTypeEffectSpecifiers()
2047+
(effectSpecifiers, yields) = self.parseTypeEffectSpecifiers()
20472048

20482049
if self.at(.arrow) {
20492050
returnClause = self.parseFunctionReturnClause(
@@ -2060,6 +2061,7 @@ extension Parser {
20602061
capture: captures,
20612062
parameterClause: parameterClause,
20622063
effectSpecifiers: effectSpecifiers,
2064+
yieldsClause: yields,
20632065
returnClause: returnClause,
20642066
unexpectedBeforeInKeyword,
20652067
inKeyword: inKeyword,
@@ -2697,6 +2699,15 @@ extension Parser.Lookahead {
26972699
}
26982700
}
26992701

2702+
// Consume 'yields'
2703+
mutating func consumeYields() {
2704+
if self.consume(if: .keyword(.yields)) != nil, self.consume(if: .leftParen) != nil {
2705+
_ = self.canParseTypeAttributeList()
2706+
_ = self.canParseSimpleOrCompositionType()
2707+
self.consume(if: .rightParen)
2708+
}
2709+
}
2710+
27002711
mutating func canParseClosureSignature() -> Bool {
27012712
// Consume attributes.
27022713
var lookahead = self.lookahead()

Sources/SwiftParser/Specifiers.swift

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#if compiler(>=6)
14-
@_spi(RawSyntax) public import SwiftSyntax
14+
@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) public import SwiftSyntax
1515
#else
16-
@_spi(RawSyntax) import SwiftSyntax
16+
@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) import SwiftSyntax
1717
#endif
1818

1919
// MARK: - TokenSpecSet
@@ -620,7 +620,39 @@ extension Parser {
620620
)
621621
}
622622

623-
private mutating func parseEffectSpecifiers<S: RawEffectSpecifiersTrait>(_: S.Type) -> S? {
623+
mutating func parseYields() -> RawYieldsClauseSyntax? {
624+
let (unexpectedBeforeYields, yieldsKeyword) = self.expect(.keyword(.yields))
625+
// If there is no `yields` at all, then let result type parsing handle everything else
626+
if yieldsKeyword.isMissing {
627+
return nil
628+
}
629+
630+
guard let leftParen = self.consume(if: .leftParen) else {
631+
return RawYieldsClauseSyntax(
632+
unexpectedBeforeYields,
633+
yieldsKeyword: yieldsKeyword,
634+
leftParen: nil,
635+
type: nil,
636+
rightParen: nil,
637+
arena: self.arena
638+
)
639+
}
640+
641+
let type = self.parseType()
642+
let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
643+
644+
return RawYieldsClauseSyntax(
645+
unexpectedBeforeYields,
646+
yieldsKeyword: yieldsKeyword,
647+
leftParen: leftParen,
648+
type: type,
649+
unexpectedBeforeRightParen,
650+
rightParen: rightParen,
651+
arena: self.arena
652+
)
653+
}
654+
655+
private mutating func parseEffectSpecifiers<S: RawEffectSpecifiersTrait>(_: S.Type) -> (S?, RawYieldsClauseSyntax?) {
624656
var unexpectedBeforeAsync: [RawSyntax] = []
625657
var asyncKeyword: RawTokenSyntax? = nil
626658
var unexpectedBeforeThrows: [RawSyntax] = []
@@ -690,32 +722,37 @@ extension Parser {
690722
}
691723
}
692724

725+
let yields = parseYields()
726+
693727
if unexpectedBeforeAsync.isEmpty && asyncKeyword == nil && unexpectedBeforeThrows.isEmpty && throwsClause == nil
694728
&& unexpectedAfterThrowsClause.isEmpty
695729
{
696-
return nil
730+
return (nil, yields)
697731
}
698732

699-
return S(
700-
RawUnexpectedNodesSyntax(unexpectedBeforeAsync, arena: self.arena),
701-
asyncSpecifier: asyncKeyword,
702-
RawUnexpectedNodesSyntax(unexpectedBeforeThrows, arena: self.arena),
703-
throwsClause: throwsClause,
704-
RawUnexpectedNodesSyntax(unexpectedAfterThrowsClause, arena: self.arena),
705-
arena: self.arena
733+
return (
734+
S(
735+
RawUnexpectedNodesSyntax(unexpectedBeforeAsync, arena: self.arena),
736+
asyncSpecifier: asyncKeyword,
737+
RawUnexpectedNodesSyntax(unexpectedBeforeThrows, arena: self.arena),
738+
throwsClause: throwsClause,
739+
RawUnexpectedNodesSyntax(unexpectedAfterThrowsClause, arena: self.arena),
740+
arena: self.arena
741+
),
742+
yields
706743
)
707744
}
708745

709-
mutating func parseTypeEffectSpecifiers() -> RawTypeEffectSpecifiersSyntax? {
746+
mutating func parseTypeEffectSpecifiers() -> (RawTypeEffectSpecifiersSyntax?, RawYieldsClauseSyntax?) {
710747
return parseEffectSpecifiers(RawTypeEffectSpecifiersSyntax.self)
711748
}
712749

713-
mutating func parseFunctionEffectSpecifiers() -> RawFunctionEffectSpecifiersSyntax? {
750+
mutating func parseFunctionEffectSpecifiers() -> (RawFunctionEffectSpecifiersSyntax?, RawYieldsClauseSyntax?) {
714751
return parseEffectSpecifiers(RawFunctionEffectSpecifiersSyntax.self)
715752
}
716753

717754
mutating func parseAccessorEffectSpecifiers() -> RawAccessorEffectSpecifiersSyntax? {
718-
return parseEffectSpecifiers(RawAccessorEffectSpecifiersSyntax.self)
755+
return parseEffectSpecifiers(RawAccessorEffectSpecifiersSyntax.self).0
719756
}
720757

721758
mutating func parseDeinitEffectSpecifiers() -> RawDeinitializerEffectSpecifiersSyntax? {

0 commit comments

Comments
 (0)