Skip to content

Commit e929c52

Browse files
authored
Merge pull request #801 from CodaFi/block-and-tackle
Another Bundle of Parser Fixes
2 parents 79d0407 + b6bf02e commit e929c52

36 files changed

+822
-74
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,16 @@ extension TokenConsumer {
3030
_ = subparser.consumeAttributeList()
3131
}
3232

33-
var modifierProgress = LoopProgressCondition()
34-
while let (modifierKind, handle) = subparser.at(anyIn: DeclarationModifier.self),
35-
modifierKind != .classKeyword,
36-
modifierProgress.evaluate(subparser.currentToken) {
37-
subparser.eat(handle)
38-
if subparser.at(.leftParen) {
39-
subparser.consumeAnyToken()
40-
subparser.consume(to: .rightParen)
33+
if subparser.currentToken.isKeyword {
34+
var modifierProgress = LoopProgressCondition()
35+
while let (modifierKind, handle) = subparser.at(anyIn: DeclarationModifier.self),
36+
modifierKind != .classKeyword,
37+
modifierProgress.evaluate(subparser.currentToken) {
38+
subparser.eat(handle)
39+
if subparser.at(.leftParen) {
40+
subparser.consumeAnyToken()
41+
subparser.consume(to: .rightParen)
42+
}
4143
}
4244
}
4345

@@ -75,10 +77,17 @@ extension TokenConsumer {
7577
lookahead.consumeAnyToken()
7678
} while lookahead.atStartOfDeclaration()
7779
return lookahead.at(.identifier)
78-
case .caseKeyword, nil:
80+
case .caseKeyword:
7981
// When 'case' appears inside a function, it's probably a switch
8082
// case, not an enum case declaration.
8183
return false
84+
case nil:
85+
if subparser.at(anyIn: ContextualDeclKeyword.self)?.0 != nil {
86+
subparser.consumeAnyToken()
87+
return subparser.atStartOfDeclaration(
88+
isAtTopLevel: isAtTopLevel, allowRecovery: allowRecovery)
89+
}
90+
return false
8291
default: return true
8392
}
8493
}
@@ -321,6 +330,13 @@ extension Parser {
321330
} while keepGoing != nil && loopProgress.evaluate(currentToken)
322331
}
323332

333+
let whereClause: RawGenericWhereClauseSyntax?
334+
if self.at(.whereKeyword) {
335+
whereClause = self.parseGenericWhereClause()
336+
} else {
337+
whereClause = nil
338+
}
339+
324340
let rangle: RawTokenSyntax
325341
if self.currentToken.starts(with: ">") {
326342
rangle = self.consumeAnyToken(remapping: .rightAngle)
@@ -337,6 +353,7 @@ extension Parser {
337353
return RawGenericParameterClauseSyntax(
338354
leftAngleBracket: langle,
339355
genericParameterList: parameters,
356+
genericWhereClause: whereClause,
340357
rightAngleBracket: rangle,
341358
arena: self.arena)
342359
}
@@ -1154,7 +1171,7 @@ extension Parser {
11541171

11551172
// Parse the '!' or '?' for a failable initializer.
11561173
let failable: RawTokenSyntax?
1157-
if let parsedFailable = self.consume(ifAny: [.exclamationMark, .postfixQuestionMark]) {
1174+
if let parsedFailable = self.consume(ifAny: [.exclamationMark, .postfixQuestionMark, .infixQuestionMark]) {
11581175
failable = parsedFailable
11591176
} else if let parsedFailable = self.consumeIfContextualPunctuator("!") {
11601177
failable = parsedFailable
@@ -1373,7 +1390,7 @@ extension Parser {
13731390
} else {
13741391
unexpectedBeforeReturnType = nil
13751392
}
1376-
let result = self.parseType()
1393+
let result = self.parseResultType()
13771394
let returnClause = RawReturnClauseSyntax(
13781395
unexpectedBeforeArrow,
13791396
arrow: arrow,

Sources/SwiftParser/Expressions.swift

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -962,14 +962,21 @@ extension Parser {
962962
@_spi(RawSyntax)
963963
public mutating func parseIdentifierExpression() -> RawExprSyntax {
964964
let (name, args) = self.parseDeclNameRef(.compoundNames)
965-
let identifier = RawIdentifierExprSyntax(
966-
identifier: name, declNameArguments: args,
967-
arena: self.arena)
968-
969965
guard self.lookahead().canParseAsGenericArgumentList() else {
970-
return RawExprSyntax(identifier)
966+
if name.tokenText.hasPrefix("<#") && name.tokenText.hasSuffix("#>") && args == nil {
967+
return RawExprSyntax(
968+
RawEditorPlaceholderExprSyntax(
969+
identifier: name,
970+
arena: self.arena))
971+
}
972+
return RawExprSyntax(RawIdentifierExprSyntax(
973+
identifier: name, declNameArguments: args,
974+
arena: self.arena))
971975
}
972976

977+
let identifier = RawIdentifierExprSyntax(
978+
identifier: name, declNameArguments: args,
979+
arena: self.arena)
973980
let generics = self.parseGenericArguments()
974981
return RawExprSyntax(RawSpecializeExprSyntax(
975982
expression: RawExprSyntax(identifier), genericArgumentClause: generics,
@@ -1794,7 +1801,7 @@ extension Parser {
17941801
// At this point, we know we have a closure signature. Parse the capture list
17951802
// and parameters.
17961803
var elements = [RawClosureCaptureItemSyntax]()
1797-
do {
1804+
if !self.at(.rightSquareBracket) {
17981805
var keepGoing: RawTokenSyntax? = nil
17991806
var loopProgress = LoopProgressCondition()
18001807
repeat {

Sources/SwiftParser/Lexer.swift

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -904,7 +904,6 @@ extension Lexer.Cursor {
904904
_ = self.advanceToEndOfLine()
905905
continue
906906
case UInt8(ascii: "*"):
907-
self = start
908907
_ = self.advanceToEndOfSlashStarComment()
909908
continue
910909
default:
@@ -1605,10 +1604,10 @@ extension Lexer.Cursor {
16051604
if !self.isAtEndOfFile, self.peek() == UInt8(ascii: ".") && TokStart.peek() != UInt8(ascii: ".") {
16061605
break
16071606
}
1608-
// if (Identifier::isEditorPlaceholder(StringRef(CurPtr, BufferEnd-CurPtr)) &&
1609-
// rangeContainsPlaceholderEnd(CurPtr + 2, BufferEnd)) {
1610-
// break
1611-
// }
1607+
let text = SyntaxText(baseAddress: self.input.baseAddress, count: self.input.count)
1608+
if text.hasPrefix("<#") && text.containsPlaceholderEnd() {
1609+
break
1610+
}
16121611

16131612
// // If we are lexing a `/.../` regex literal, we don't consider `/` to be an
16141613
// // operator character.
@@ -2055,6 +2054,13 @@ extension Lexer.Cursor {
20552054
case nil:
20562055
return nil
20572056
case UInt8(ascii: "/"):
2057+
// If we're at the end of the literal, peek ahead to see if the closing
2058+
// slash is actually the start of a comment.
2059+
if !Tmp.isAtEndOfFile &&
2060+
(Tmp.peek() == UInt8(ascii: "/") || Tmp.peek() == UInt8(ascii: "*")) {
2061+
return nil
2062+
}
2063+
20582064
var EndLex = Tmp
20592065
for _ in 0..<poundCount {
20602066
guard EndLex.advance(matching: UInt8(ascii: "#")) != nil else {
@@ -2257,3 +2263,23 @@ extension Unicode.Scalar {
22572263
return self.value >= 0x20 && self.value < 0x7F
22582264
}
22592265
}
2266+
2267+
extension SyntaxText {
2268+
fileprivate func containsPlaceholderEnd() -> Bool {
2269+
guard self.count >= 2 else {
2270+
return false
2271+
}
2272+
2273+
for idx in 0..<(self.count - 1) {
2274+
let c = self[idx]
2275+
guard c != UInt8(ascii: "\n") else {
2276+
return false
2277+
}
2278+
2279+
if self[idx] == UInt8(ascii: "#"), self[idx+1] == UInt8(ascii: ">") {
2280+
return true
2281+
}
2282+
}
2283+
return false
2284+
}
2285+
}

Sources/SwiftParser/Names.swift

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ extension Parser {
132132
let type: RawTypeSyntax?
133133
let dot: RawTokenSyntax?
134134
if self.lookahead().canParseBaseTypeForQualifiedDeclName() {
135-
type = self.parseTypeIdentifier()
135+
type = self.parseQualifiedTypeIdentifier()
136136
dot = self.consumePrefix(".", as: .period)
137137
} else {
138138
type = nil
@@ -151,6 +151,50 @@ extension Parser {
151151
arguments: args,
152152
arena: self.arena)
153153
}
154+
155+
@_spi(RawSyntax)
156+
public mutating func parseQualifiedTypeIdentifier() -> RawTypeSyntax {
157+
if self.at(.anyKeyword) {
158+
return RawTypeSyntax(self.parseAnyType())
159+
}
160+
161+
var result: RawTypeSyntax?
162+
var keepGoing: RawTokenSyntax? = nil
163+
var loopProgress = LoopProgressCondition()
164+
repeat {
165+
let (name, _) = self.parseDeclNameRef()
166+
let generics: RawGenericArgumentClauseSyntax?
167+
if self.atContextualPunctuator("<") {
168+
generics = self.parseGenericArguments()
169+
} else {
170+
generics = nil
171+
}
172+
if let keepGoing = keepGoing {
173+
result = RawTypeSyntax(RawMemberTypeIdentifierSyntax(
174+
baseType: result!,
175+
period: keepGoing,
176+
name: name,
177+
genericArgumentClause: generics,
178+
arena: self.arena))
179+
} else {
180+
result = RawTypeSyntax(RawSimpleTypeIdentifierSyntax(
181+
name: name, genericArgumentClause: generics, arena: self.arena))
182+
}
183+
184+
// If qualified name base type cannot be parsed from the current
185+
// point (i.e. the next type identifier is not followed by a '.'),
186+
// then the next identifier is the final declaration name component.
187+
var backtrack = self.lookahead()
188+
backtrack.consumePrefix(".", as: .period)
189+
guard backtrack.canParseBaseTypeForQualifiedDeclName() else {
190+
break
191+
}
192+
193+
keepGoing = self.consume(if: .period) ?? self.consume(if: .prefixPeriod)
194+
} while keepGoing != nil && loopProgress.evaluate(currentToken)
195+
196+
return result!
197+
}
154198
}
155199

156200
extension Parser.Lookahead {

Sources/SwiftParser/Patterns.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ extension Parser {
117117
return (pattern, nil)
118118
}
119119

120-
let result = self.parseType()
120+
let result = self.parseResultType()
121121
let type = RawTypeAnnotationSyntax(
122122
colon: colon,
123123
type: result,

Sources/SwiftParser/Types.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ extension Parser {
185185
) {
186186
base = RawTypeSyntax(RawMetatypeTypeSyntax(
187187
baseType: base, period: period, typeOrProtocol: type, arena: self.arena))
188-
}
188+
continue
189+
}
189190

190191
if !self.currentToken.isAtStartOfLine {
191192
if self.currentToken.isOptionalToken {
@@ -860,6 +861,22 @@ extension Parser {
860861
}
861862
}
862863

864+
extension Parser {
865+
mutating func parseResultType() -> RawTypeSyntax {
866+
if self.currentToken.starts(with: "<") {
867+
let generics = self.parseGenericParameters()
868+
let baseType = self.parseType()
869+
return RawTypeSyntax(
870+
RawNamedOpaqueReturnTypeSyntax(
871+
genericParameters: generics,
872+
baseType: baseType,
873+
arena: self.arena))
874+
} else {
875+
return self.parseType()
876+
}
877+
}
878+
}
879+
863880
extension Lexer.Lexeme {
864881
var isBinaryOperator: Bool {
865882
return self.tokenKind == .spacedBinaryOperator

Sources/SwiftSyntax/Documentation.docc/gyb_generated/SwiftSyntax.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ allows Swift tools to parse, inspect, generate, and transform Swift source code.
177177
- <doc:SwiftSyntax/TupleTypeSyntax>
178178
- <doc:SwiftSyntax/FunctionTypeSyntax>
179179
- <doc:SwiftSyntax/AttributedTypeSyntax>
180+
- <doc:SwiftSyntax/NamedOpaqueReturnTypeSyntax>
180181

181182
### Patterns
182183

0 commit comments

Comments
 (0)