Skip to content

Commit ca2d3d2

Browse files
committed
Address review comments
1 parent 3ab3742 commit ca2d3d2

15 files changed

+295
-200
lines changed

Sources/SwiftParser/Lexer/Cursor.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,8 +1734,8 @@ extension Lexer.Cursor {
17341734
if stringLiteralKind == .multiLine {
17351735
// Make sure each line starts a new string segment so the parser can
17361736
// validate the multi-line string literal's indentation.
1737-
let charcter = self.advance()
1738-
if charcter == UInt8(ascii: "\r") {
1737+
let character = self.advance()
1738+
if character == UInt8(ascii: "\r") {
17391739
_ = self.advance(matching: "\n")
17401740
}
17411741
return Lexer.Result(.stringSegment)

Sources/SwiftParser/StringLiterals.swift

Lines changed: 204 additions & 147 deletions
Large diffs are not rendered by default.

Sources/SwiftParser/TriviaParser.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ public struct TriviaParser {
9797
continue
9898
}
9999

100+
case UInt8(ascii: "\\"):
101+
cursor.advance(while: { $0 == "\\" })
102+
pieces.append(.backslashes(start.distance(to: cursor)))
103+
continue
104+
100105
default:
101106
break
102107
}

Sources/SwiftParserDiagnostics/DiagnosticExtensions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ extension Trivia {
174174
return Array(repeating: TriviaPiece.formfeeds(1), count: count)
175175
case .newlines(let count):
176176
return Array(repeating: TriviaPiece.newlines(1), count: count)
177-
case .backslashs(let count):
178-
return Array(repeating: TriviaPiece.backslashs(1), count: count)
177+
case .backslashes(let count):
178+
return Array(repeating: TriviaPiece.backslashes(1), count: count)
179179
case .carriageReturns(let count):
180180
return Array(repeating: TriviaPiece.carriageReturns(1), count: count)
181181
case .carriageReturnLineFeeds(let count):

Sources/SwiftParserDiagnostics/LexerDiagnosticMessages.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public extension SwiftSyntax.LexerError {
114114
// This should be diagnosed when visiting the `StringLiteralExprSyntax`
115115
// inside `ParseDiagnosticsGenerator` but fall back to an error message
116116
// here in case the error is not diagnosed.
117-
return InvalidIndentationInMultiLineStringLiteralError(kind: .insufficientIdentation, lines: 1)
117+
return InvalidIndentationInMultiLineStringLiteralError(kind: .insufficientIndentation, lines: 1)
118118
case .invalidBinaryDigitInIntegerLiteral:
119119
return InvalidDigitInIntegerLiteral(kind: .binary(scalarAtErrorOffset))
120120
case .invalidDecimalDigitInIntegerLiteral:

Sources/SwiftParserDiagnostics/MultiLineStringLiteralDiagnoticsGenerator.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ final class MultiLineStringLiteralIndentatinDiagnosticsGenerator: SyntaxVisitor
4040

4141
private let closeQuote: TokenSyntax
4242

43-
/// Diagnostics that we have finisehed because their incorrect indentation was followed by correct indentation
43+
/// Diagnostics that we have finished because their incorrect indentation was followed by correct indentation
4444
private var finishedDiagnostics: [(diagnostic: Diagnostic, handledNodes: [SyntaxIdentifier])] = []
4545

4646
/// The diagnostic we are currently building up
@@ -53,15 +53,15 @@ final class MultiLineStringLiteralIndentatinDiagnosticsGenerator: SyntaxVisitor
5353

5454
private func addIncorrectlyIndentedToken(token: TokenSyntax) {
5555
// Determine kind and position of the diagnonstic
56-
var kind: InvalidIndentationInMultiLineStringLiteralError.Kind = .insufficientIdentation
56+
var kind: InvalidIndentationInMultiLineStringLiteralError.Kind = .insufficientIndentation
5757
var position = token.positionAfterSkippingLeadingTrivia
5858

5959
let tokenLeadingTrivia = token.leadingTrivia
6060

6161
let indentationStartIndex = tokenLeadingTrivia.pieces.lastIndex(where: { $0.isNewline })?.advanced(by: 1) ?? tokenLeadingTrivia.startIndex
6262
let preIndentationTrivia = Trivia(pieces: tokenLeadingTrivia[0..<indentationStartIndex])
6363
let indentationTrivia = Trivia(pieces: tokenLeadingTrivia[indentationStartIndex...])
64-
var positionOffset = preIndentationTrivia.reduce(0, { $0 + $1.sourceLength.utf8Length })
64+
var positionOffset = preIndentationTrivia.byteSize
6565

6666
for (invalidTriviaPiece, missingTriviaPiece) in zip(indentationTrivia.decomposed, closeQuote.leadingTrivia.decomposed) {
6767
if invalidTriviaPiece == missingTriviaPiece {
@@ -83,7 +83,7 @@ final class MultiLineStringLiteralIndentatinDiagnosticsGenerator: SyntaxVisitor
8383
finishInProgressDiagnostic()
8484
}
8585

86-
// Append hte inProgress diagnostic or create a new one.
86+
// Append the inProgressDiagnostic or create a new one.
8787
let changes = [FixIt.Change.replaceLeadingTrivia(token: token, newTrivia: preIndentationTrivia + closeQuote.leadingTrivia)]
8888
let handledNodes = [token.id]
8989
if self.inProgressDiagnostic != nil {

Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,13 +278,13 @@ public struct InvalidIdentifierError: ParserError {
278278

279279
public struct InvalidIndentationInMultiLineStringLiteralError: ParserError {
280280
public enum Kind {
281-
case insufficientIdentation
281+
case insufficientIndentation
282282
case unexpectedSpace
283283
case unexpectedTab
284284

285285
var message: String {
286286
switch self {
287-
case .insufficientIdentation: return "insufficient indentation"
287+
case .insufficientIndentation: return "insufficient indentation"
288288
case .unexpectedSpace: return "unexpected space in indentation"
289289
case .unexpectedTab: return "unexpected tab in indentation"
290290
}
@@ -298,7 +298,7 @@ public struct InvalidIndentationInMultiLineStringLiteralError: ParserError {
298298
if lines == 1 {
299299
return "\(kind.message) of line in multi-line string literal"
300300
} else {
301-
return "\(kind.message) of next \(lines) lines in multi-line string literal"
301+
return "\(kind.message) of the next \(lines) lines in multi-line string literal"
302302
}
303303
}
304304
}

Sources/SwiftSyntax/Raw/RawSyntax.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -873,14 +873,12 @@ extension RawSyntax: CustomReflectable {
873873
}
874874
}
875875

876-
@_spi(RawSyntax)
877-
public enum RawSyntaxView {
876+
enum RawSyntaxView {
878877
case token(RawSyntaxTokenView)
879878
case layout(RawSyntaxLayoutView)
880879
}
881880

882-
@_spi(RawSyntax)
883-
public extension RawSyntax {
881+
extension RawSyntax {
884882
var view: RawSyntaxView {
885883
switch raw.payload {
886884
case .parsedToken, .materializedToken:

Sources/SwiftSyntax/Raw/RawSyntaxNodeProtocol.swift

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,10 @@ public struct RawTokenSyntax: RawSyntaxNodeProtocol {
243243
let extendedTriviaByteLength = extendedTrivia.reduce(0, { $0 + $1.byteLength })
244244
switch raw.rawData.payload {
245245
case .parsedToken(let dat):
246-
assert(String(syntaxText: SyntaxText(baseAddress: dat.wholeText.baseAddress?.advanced(by: -extendedTriviaByteLength), count: extendedTriviaByteLength)) == Trivia(pieces: extendedTrivia.map(TriviaPiece.init)).description)
246+
assert(
247+
String(syntaxText: SyntaxText(baseAddress: dat.wholeText.baseAddress?.advanced(by: -extendedTriviaByteLength), count: extendedTriviaByteLength))
248+
== Trivia(pieces: extendedTrivia.map(TriviaPiece.init)).description
249+
)
247250
let wholeText = SyntaxText(baseAddress: dat.wholeText.baseAddress?.advanced(by: -extendedTriviaByteLength), count: dat.wholeText.count + extendedTriviaByteLength)
248251
let textRange = (dat.textRange.lowerBound + extendedTriviaByteLength)..<(dat.textRange.upperBound + extendedTriviaByteLength)
249252
return RawSyntax.parsedToken(
@@ -283,8 +286,10 @@ public struct RawTokenSyntax: RawSyntaxNodeProtocol {
283286
let extendedTriviaByteLength = extendedTrivia.reduce(0, { $0 + $1.byteLength })
284287
switch raw.rawData.payload {
285288
case .parsedToken(let dat):
286-
// TODO: Can we write this assert easier using subscript slicing?
287-
assert(String(syntaxText: SyntaxText(baseAddress: dat.wholeText.baseAddress?.advanced(by: dat.wholeText.count), count: extendedTriviaByteLength)) == Trivia(pieces: extendedTrivia.map(TriviaPiece.init)).description)
289+
assert(
290+
String(syntaxText: SyntaxText(baseAddress: dat.wholeText.baseAddress?.advanced(by: dat.wholeText.count), count: extendedTriviaByteLength))
291+
== Trivia(pieces: extendedTrivia.map(TriviaPiece.init)).description
292+
)
288293
let wholeText = SyntaxText(baseAddress: dat.wholeText.baseAddress, count: dat.wholeText.count + extendedTriviaByteLength)
289294
return RawSyntax.parsedToken(
290295
kind: dat.tokenKind,
@@ -321,10 +326,12 @@ public struct RawTokenSyntax: RawSyntaxNodeProtocol {
321326
/// that error will be set as the lexer error.
322327
public func reclassifyAsLeadingTrivia(_ reclassifiedTrivia: [RawTriviaPiece], lexerError: LexerError? = nil, arena: SyntaxArena) -> RawTokenSyntax {
323328
let reclassifiedTriviaByteLength = reclassifiedTrivia.reduce(0, { $0 + $1.byteLength })
324-
assert(String(syntaxText: SyntaxText(rebasing: self.tokenText[0..<reclassifiedTriviaByteLength])) == Trivia(pieces: reclassifiedTrivia.map(TriviaPiece.init)).description)
329+
assert(
330+
String(syntaxText: SyntaxText(rebasing: self.tokenText[0..<reclassifiedTriviaByteLength]))
331+
== Trivia(pieces: reclassifiedTrivia.map(TriviaPiece.init)).description
332+
)
325333
switch raw.rawData.payload {
326334
case .parsedToken(let dat):
327-
assert(String(syntaxText: SyntaxText(rebasing: dat.tokenText[0..<reclassifiedTriviaByteLength])) == Trivia(pieces: reclassifiedTrivia.map(TriviaPiece.init)).description)
328335
let textRange = (dat.textRange.lowerBound + reclassifiedTriviaByteLength)..<dat.textRange.upperBound
329336
return RawSyntax.parsedToken(
330337
kind: dat.tokenKind,
@@ -335,7 +342,6 @@ public struct RawTokenSyntax: RawSyntaxNodeProtocol {
335342
arena: arena
336343
).as(RawTokenSyntax.self)!
337344
case .materializedToken(let dat):
338-
assert(String(syntaxText: SyntaxText(rebasing: dat.tokenText[0..<reclassifiedTriviaByteLength])) == Trivia(pieces: reclassifiedTrivia.map(TriviaPiece.init)).description)
339345
let triviaBuffer = arena.allocateRawTriviaPieceBuffer(count: dat.triviaPieces.count + reclassifiedTrivia.count)
340346
let (_, existingLeadingTriviaEndIndex) = triviaBuffer.initialize(from: dat.leadingTrivia)
341347
let (_, reclassifiedTriviaEndIndex) = triviaBuffer[existingLeadingTriviaEndIndex...].initialize(from: reclassifiedTrivia)
@@ -363,7 +369,10 @@ public struct RawTokenSyntax: RawSyntaxNodeProtocol {
363369
/// that error will be set as the lexer error.
364370
public func reclassifyAsTrailingTrivia(_ reclassifiedTrivia: [RawTriviaPiece], lexerError: LexerError? = nil, arena: SyntaxArena) -> RawTokenSyntax {
365371
let reclassifiedTriviaByteLength = reclassifiedTrivia.reduce(0, { $0 + $1.byteLength })
366-
assert(String(syntaxText: SyntaxText(rebasing: self.tokenText[(self.tokenText.count - reclassifiedTriviaByteLength)...])) == Trivia(pieces: reclassifiedTrivia.map(TriviaPiece.init)).description)
372+
assert(
373+
String(syntaxText: SyntaxText(rebasing: self.tokenText[(self.tokenText.count - reclassifiedTriviaByteLength)...]))
374+
== Trivia(pieces: reclassifiedTrivia.map(TriviaPiece.init)).description
375+
)
367376
switch raw.rawData.payload {
368377
case .parsedToken(let dat):
369378
let textRange = dat.textRange.lowerBound..<(dat.textRange.upperBound - reclassifiedTriviaByteLength)

Sources/SwiftSyntax/Raw/RawSyntaxTokenView.swift

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public struct RawSyntaxTokenView {
6161
case .materializedToken(let dat):
6262
return dat.tokenText
6363
case .layout(_):
64-
preconditionFailure("'tokenText' is not available for non-token node")
64+
preconditionFailure("'rawText' is not available for non-token node")
6565
}
6666
}
6767

@@ -74,7 +74,7 @@ public struct RawSyntaxTokenView {
7474
case .materializedToken(let dat):
7575
return dat.leadingTrivia.reduce(0) { $0 + $1.byteLength }
7676
case .layout(_):
77-
preconditionFailure("'tokenLeadingTriviaByteLength' is not available for non-token node")
77+
preconditionFailure("'leadingTriviaByteLength' is not available for non-token node")
7878
}
7979
}
8080

@@ -87,7 +87,7 @@ public struct RawSyntaxTokenView {
8787
case .materializedToken(let dat):
8888
return dat.trailingTrivia.reduce(0) { $0 + $1.byteLength }
8989
case .layout(_):
90-
preconditionFailure("'tokenTrailingTriviaByteLength' is not available for non-token node")
90+
preconditionFailure("'trailingTriviaByteLength' is not available for non-token node")
9191
}
9292
}
9393

@@ -100,7 +100,7 @@ public struct RawSyntaxTokenView {
100100
case .materializedToken(let dat):
101101
return Array(dat.leadingTrivia)
102102
case .layout(_):
103-
preconditionFailure("'tokenLeadingRawTriviaPieces' is called on non-token raw syntax")
103+
preconditionFailure("'leadingRawTriviaPieces' is called on non-token raw syntax")
104104
}
105105
}
106106

@@ -113,7 +113,7 @@ public struct RawSyntaxTokenView {
113113
case .materializedToken(let dat):
114114
return Array(dat.trailingTrivia)
115115
case .layout(_):
116-
preconditionFailure("'tokenTrailingRawTriviaPieces' is called on non-token raw syntax")
116+
preconditionFailure("'trailingRawTriviaPieces' is called on non-token raw syntax")
117117
}
118118
}
119119

@@ -129,7 +129,7 @@ public struct RawSyntaxTokenView {
129129
return SourceLength(utf8Length: trailingTriviaByteLength)
130130
}
131131

132-
/// Perform `body` with text of th leading trivia.
132+
/// Run `body` with text of the leading trivia and return its result.
133133
@_spi(RawSyntax)
134134
public func leadingTrivia<T>(_ body: (SyntaxText) -> T) -> T {
135135
switch raw.rawData.payload {
@@ -139,11 +139,11 @@ public struct RawSyntaxTokenView {
139139
var leadingTriviaStr = Trivia(pieces: dat.leadingTrivia.map(TriviaPiece.init)).description
140140
return leadingTriviaStr.withSyntaxText(body)
141141
case .layout(_):
142-
preconditionFailure("'tokenTrailingRawTriviaPieces' is called on non-token raw syntax")
142+
preconditionFailure("'leadingTrivia' is called on non-token raw syntax")
143143
}
144144
}
145145

146-
/// Perform `body` with text of th trailing trivia.
146+
/// Run `body` with text of the leading trivia and return its result.
147147
@_spi(RawSyntax)
148148
public func trailingTrivia<T>(_ body: (SyntaxText) -> T) -> T {
149149
switch raw.rawData.payload {
@@ -153,7 +153,7 @@ public struct RawSyntaxTokenView {
153153
var trailingTriviaStr = Trivia(pieces: dat.trailingTrivia.map(TriviaPiece.init)).description
154154
return trailingTriviaStr.withSyntaxText(body)
155155
case .layout(_):
156-
preconditionFailure("'tokenTrailingRawTriviaPieces' is called on non-token raw syntax")
156+
preconditionFailure("'trailingTrivia' is called on non-token raw syntax")
157157
}
158158
}
159159

@@ -193,7 +193,7 @@ public struct RawSyntaxTokenView {
193193
payload.tokenText = text
194194
return RawSyntax(arena: arena, payload: .materializedToken(payload))
195195
default:
196-
preconditionFailure("'withTokenKind()' is called on non-token raw syntax")
196+
preconditionFailure("'withKind()' is called on non-token raw syntax")
197197
}
198198
}
199199

@@ -207,7 +207,7 @@ public struct RawSyntaxTokenView {
207207
case .materializedToken(let dat):
208208
return dat.tokenText.count
209209
case .layout(_):
210-
preconditionFailure("'tokenTextByteLength' is not available for non-token node")
210+
preconditionFailure("'textByteLength' is not available for non-token node")
211211
}
212212
}
213213

@@ -224,7 +224,7 @@ public struct RawSyntaxTokenView {
224224
case .materializedToken(let dat):
225225
return TokenKind.fromRaw(kind: dat.tokenKind, text: String(syntaxText: dat.tokenText))
226226
case .layout(_):
227-
preconditionFailure("Must be invoked on a token")
227+
preconditionFailure("'formKind' is not available for non-token node")
228228
}
229229
}
230230

@@ -236,7 +236,7 @@ public struct RawSyntaxTokenView {
236236
case .materializedToken(let dat):
237237
return dat.presence
238238
case .layout(_):
239-
preconditionFailure("'presence' is a token-only property")
239+
preconditionFailure("'presence' is not available for non-token node")
240240
}
241241
}
242242

@@ -248,7 +248,7 @@ public struct RawSyntaxTokenView {
248248
case .materializedToken(let dat):
249249
return dat.lexerError
250250
case .layout(_):
251-
preconditionFailure("'lexerError' is a token-only property")
251+
preconditionFailure("'lexerError' is not available for non-token node")
252252
}
253253
}
254254

@@ -262,7 +262,7 @@ public struct RawSyntaxTokenView {
262262
dat.lexerError = lexerError
263263
return RawSyntax(arena: arena, payload: .materializedToken(dat))
264264
default:
265-
preconditionFailure("'withLexerError()' is called on non-token raw syntax")
265+
preconditionFailure("'withLexerError' is not available for non-token node")
266266
}
267267
}
268268
}

Sources/SwiftSyntax/SourceLocation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ fileprivate extension RawTriviaPiece {
475475
let .tabs(count),
476476
let .verticalTabs(count),
477477
let .formfeeds(count),
478-
let .backslashs(count):
478+
let .backslashes(count):
479479
lineLength += SourceLength(utf8Length: count)
480480
case let .newlines(count),
481481
let .carriageReturns(count):

Tests/SwiftParserTest/Assertions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ public struct AssertParseOptions: OptionSet {
452452

453453
/// Replace all `\r` and `\r\n` in the fixed source by `\n`.
454454
/// Useful to match source code that contains other line endings to expected
455-
/// fixedfixed source that has `\n` line endings.
455+
/// fixed source that has `\n` line endings.
456456
public static let normalizeNewlinesInFixedSource = AssertParseOptions(rawValue: 1 << 1)
457457
}
458458

Tests/SwiftParserTest/ExpressionTests.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,7 @@ final class ExpressionTests: XCTestCase {
956956
StringLiteralExprSyntax(
957957
openQuote: .multilineStringQuoteToken(leadingTrivia: .spaces(2), trailingTrivia: .newline),
958958
segments: StringLiteralSegmentsSyntax([
959-
.stringSegment(StringSegmentSyntax(content: .stringSegment("line 1 ", leadingTrivia: .spaces(2), trailingTrivia: [.unexpectedText("\\"), .newlines(1)]))),
959+
.stringSegment(StringSegmentSyntax(content: .stringSegment("line 1 ", leadingTrivia: .spaces(2), trailingTrivia: [.backslashes(1), .newlines(1)]))),
960960
.stringSegment(StringSegmentSyntax(content: .stringSegment("line 2", leadingTrivia: .spaces(2), trailingTrivia: .newline))),
961961
]),
962962
closeQuote: .multilineStringQuoteToken(leadingTrivia: .spaces(2))
@@ -993,6 +993,17 @@ final class ExpressionTests: XCTestCase {
993993
options: [.substructureCheckTrivia]
994994
)
995995
}
996+
997+
func testMultiLineStringInInterpolationOfSingleLineStringLiteral() {
998+
// It's odd that we accept this but it matches the C++ parser's behavior.
999+
AssertParse(
1000+
#"""
1001+
"foo\(test("""
1002+
bar
1003+
""") )"
1004+
"""#
1005+
)
1006+
}
9961007
}
9971008

9981009
final class MemberExprTests: XCTestCase {

0 commit comments

Comments
 (0)