Skip to content

Commit 13b2b57

Browse files
authored
Merge pull request #737 from ahoppen/ahoppen/token-name-for-diagnostics
Use a token name for diagnostics to generate diagnostic messages
2 parents 23e54c1 + 39e2b9a commit 13b2b57

File tree

10 files changed

+483
-222
lines changed

10 files changed

+483
-222
lines changed

Sources/SwiftParser/Diagnostics/ParserDiagnosticMessages.swift

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

1313
import SwiftDiagnostics
14-
import SwiftSyntax
14+
@_spi(RawSyntax) import SwiftSyntax
1515

1616
let diagnosticDomain: String = "SwiftParser"
1717

@@ -139,22 +139,27 @@ public struct MissingTokenError: ParserError {
139139
public let missingToken: TokenSyntax
140140

141141
public var message: String {
142-
guard let parent = missingToken.parent, let parentTypeName = parent.nodeTypeNameForDiagnostics() else {
143-
return "Expected '\(missingToken.text)'"
142+
var message = "Expected"
143+
if missingToken.text.isEmpty {
144+
message += " \(missingToken.tokenKind.decomposeToRaw().rawKind.nameForDiagnostics)"
145+
} else {
146+
message += " '\(missingToken.text)'"
144147
}
145-
switch missingToken.tokenKind {
146-
case .leftAngle, .leftBrace, .leftParen, .leftSquareBracket:
147-
if parent.children(viewMode: .fixedUp).first?.as(TokenSyntax.self) == missingToken {
148-
return "Expected '\(missingToken.text)' to start \(parentTypeName)"
149-
}
150-
case .rightAngle, .rightBrace, .rightParen, .rightSquareBracket:
151-
if parent.children(viewMode: .fixedUp).last?.as(TokenSyntax.self) == missingToken {
152-
return "Expected '\(missingToken.text)' to end \(parentTypeName)"
148+
if let parent = missingToken.parent, let parentTypeName = parent.nodeTypeNameForDiagnostics() {
149+
switch missingToken.tokenKind {
150+
case .leftAngle, .leftBrace, .leftParen, .leftSquareBracket:
151+
if parent.children(viewMode: .fixedUp).first?.as(TokenSyntax.self) == missingToken {
152+
message += " to start \(parentTypeName)"
153+
}
154+
case .rightAngle, .rightBrace, .rightParen, .rightSquareBracket:
155+
if parent.children(viewMode: .fixedUp).last?.as(TokenSyntax.self) == missingToken {
156+
message += " to end \(parentTypeName)"
157+
}
158+
default:
159+
message += " in \(parentTypeName)"
153160
}
154-
default:
155-
break
156161
}
157-
return "Expected '\(missingToken.text)' in \(parentTypeName)"
162+
return message
158163
}
159164

160165
public var handledNodes: [Syntax] {

Sources/SwiftSyntax/Raw/RawSyntaxTokenView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,9 @@ struct RawSyntaxTokenView {
180180
func formKind() -> TokenKind {
181181
switch raw.rawData.payload {
182182
case .parsedToken(let dat):
183-
return TokenKind.fromRaw(kind: dat.tokenKind, text: dat.tokenText)
183+
return TokenKind.fromRaw(kind: dat.tokenKind, text: String(syntaxText: dat.tokenText))
184184
case .materializedToken(let dat):
185-
return TokenKind.fromRaw(kind: dat.tokenKind, text: dat.tokenText)
185+
return TokenKind.fromRaw(kind: dat.tokenKind, text: String(syntaxText: dat.tokenText))
186186
case .layout(_):
187187
preconditionFailure("Must be invoked on a token")
188188
}

Sources/SwiftSyntax/TokenKind.swift.gyb

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@ public enum RawTokenKind: Equatable, Hashable {
161161
}
162162
}
163163

164+
public var nameForDiagnostics: String {
165+
switch self {
166+
case .eof: return "end of file"
167+
% for token in SYNTAX_TOKENS:
168+
case .${token.swift_kind()}: return "${token.name_for_diagnostics}"
169+
% end
170+
}
171+
}
172+
164173
/// Returns `true` if the token is a Swift keyword.
165174
///
166175
/// Keywords are reserved unconditionally for use by Swift and may not
@@ -222,24 +231,26 @@ for token in SYNTAX_TOKENS:
222231

223232
extension TokenKind {
224233
/// If the `rawKind` has a `defaultText`, `text` can be empty.
225-
static func fromRaw(kind rawKind: RawTokenKind, text: SyntaxText) -> TokenKind {
234+
@_spi(RawSyntax)
235+
public static func fromRaw(kind rawKind: RawTokenKind, text: String) -> TokenKind {
226236
switch rawKind {
227237
case .eof: return .eof
228238
% for token in SYNTAX_TOKENS:
229239
case .${token.swift_kind()}:
230240
% if token.text:
231-
assert(text.isEmpty || rawKind.defaultText == text)
241+
assert(text.isEmpty || rawKind.defaultText.map(String.init) == text)
232242
return .${token.swift_kind()}
233243
% else:
234-
return .${token.swift_kind()}(String(syntaxText: text))
244+
return .${token.swift_kind()}(text)
235245
% end
236246
% end
237247
}
238248
}
239249

240250
/// Returns the `RawTokenKind` of this `TokenKind` and, if this `TokenKind`
241251
/// has associated text, the associated text, otherwise `nil`.
242-
func decomposeToRaw() -> (rawKind: RawTokenKind, string: String?) {
252+
@_spi(RawSyntax)
253+
public func decomposeToRaw() -> (rawKind: RawTokenKind, string: String?) {
243254
switch self {
244255
case .eof: return (.eof, nil)
245256
% for token in SYNTAX_TOKENS:

0 commit comments

Comments
 (0)