Skip to content

Commit 8d345e5

Browse files
authored
Merge pull request #1339 from ahoppen/ahoppen/validate-token-choices
Add a conditional compilation flag to verify token choices
2 parents 3bb2659 + bbf5297 commit 8d345e5

File tree

2 files changed

+665
-352
lines changed

2 files changed

+665
-352
lines changed

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/RawSyntaxValidationFile.swift

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,39 @@ let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: copyrightHead
3232
condition: ExprSyntax("DEBUG"),
3333
elements: .statements(
3434
try CodeBlockItemListSyntax {
35+
DeclSyntax(
36+
#"""
37+
enum TokenChoice: CustomStringConvertible {
38+
case keyword(StaticString)
39+
case tokenKind(RawTokenKind)
40+
41+
var description: String {
42+
switch self {
43+
case .keyword(let keyword):
44+
return "keyword('\(keyword)')"
45+
case .tokenKind(let kind):
46+
return "\(kind)"
47+
}
48+
}
49+
}
50+
"""#
51+
)
52+
3553
DeclSyntax(
3654
#"""
3755
enum ValidationError: CustomStringConvertible {
3856
case expectedNonNil(expectedKind: RawSyntaxNodeProtocol.Type, file: StaticString, line: UInt)
3957
case kindMismatch(expectedKind: RawSyntaxNodeProtocol.Type, actualKind: SyntaxKind, file: StaticString, line: UInt)
58+
case tokenMismatch(expectedTokenChoices: [TokenChoice], actualKind: RawTokenKind, actualText: SyntaxText, file: StaticString, line: UInt)
4059
4160
var description: String {
4261
switch self {
4362
case .expectedNonNil(expectedKind: let expectedKind, file: _, line: _):
4463
return "Expected non-nil node of type \(expectedKind) but received nil"
4564
case .kindMismatch(expectedKind: let expectedKind, actualKind: let actualKind, file: _, line: _):
4665
return "Expected node of type \(expectedKind) but received \(actualKind)"
66+
case .tokenMismatch(expectedTokenChoices: let tokenChoices, actualKind: let actualKind, actualText: let actualText, file: _, line: _):
67+
return "Expected token with one of \(tokenChoices) but received \(actualKind) with text '\(actualText)'"
4768
}
4869
}
4970
@@ -53,6 +74,8 @@ let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: copyrightHead
5374
return (file, line)
5475
case .kindMismatch(expectedKind: _, actualKind: _, file: let file, line: let line):
5576
return (file, line)
77+
case .tokenMismatch(expectedTokenChoices: _, actualKind: _, actualText: _, file: let file, line: let line):
78+
return (file, line)
5679
}
5780
}
5881
}
@@ -84,6 +107,61 @@ let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: copyrightHead
84107
"""
85108
)
86109

110+
DeclSyntax(
111+
"""
112+
func verify(_ raw: RawSyntax?, as _: RawTokenSyntax?.Type, tokenChoices: [TokenChoice], file: StaticString = #file, line: UInt = #line) -> ValidationError? {
113+
// Validation of token choice is currently causing assertion failures where
114+
// the list of expected token choices in the syntax tree doesn't match those
115+
// the parser generates. Disable the verification for now until all issues
116+
// regarding it are fixed.
117+
#if VALIDATE_TOKEN_CHOICES
118+
if raw != nil {
119+
return verify(raw, as: RawTokenSyntax.self, tokenChoices: tokenChoices, file: file, line: line)
120+
}
121+
return nil
122+
#else
123+
return verify(raw, as: RawTokenSyntax?.self)
124+
#endif
125+
}
126+
"""
127+
)
128+
129+
DeclSyntax(
130+
"""
131+
func verify(_ raw: RawSyntax?, as _: RawTokenSyntax.Type, tokenChoices: [TokenChoice], file: StaticString = #file, line: UInt = #line) -> ValidationError? {
132+
// Validation of token choice is currently causing assertion failures where
133+
// the list of expected token choices in the syntax tree doesn't match those
134+
// the parser generates. Disable the verification for now until all issues
135+
// regarding it are fixed.
136+
#if VALIDATE_TOKEN_CHOICES
137+
guard let raw = raw else {
138+
return .expectedNonNil(expectedKind: RawTokenSyntax.self, file: file, line: line)
139+
}
140+
if let error = verify(raw, as: RawTokenSyntax?.self) {
141+
return error
142+
}
143+
let tokenView = raw.tokenView!
144+
for tokenChoice in tokenChoices {
145+
switch tokenChoice {
146+
case .tokenKind(let tokenKind):
147+
if raw.tokenView?.rawKind == tokenKind {
148+
return nil
149+
}
150+
case .keyword(let keyword):
151+
if tokenView.rawKind == .keyword && tokenView.rawText == SyntaxText(keyword) {
152+
return nil
153+
}
154+
}
155+
}
156+
return ValidationError.tokenMismatch(expectedTokenChoices: tokenChoices, actualKind: tokenView.rawKind, actualText: tokenView.rawText, file: file, line: line)
157+
#else
158+
return verify(raw, as: RawTokenSyntax.self)
159+
#endif
160+
}
161+
162+
"""
163+
)
164+
87165
DeclSyntax(
88166
#"""
89167
func assertNoError(_ nodeKind: SyntaxKind, _ index: Int, _ error: ValidationError?) {
@@ -139,6 +217,19 @@ let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: copyrightHead
139217
}
140218

141219
ExprSyntax("assertAnyHasNoError(kind, \(raw: index), \(verifiedChoices))")
220+
case .token(choices: let choices, requiresLeadingSpace: _, requiresTrailingSpace: _):
221+
let choices = ArrayExprSyntax {
222+
for choice in choices {
223+
switch choice {
224+
case .keyword(text: let text):
225+
ArrayElementSyntax(expression: ExprSyntax(#".keyword("\#(raw: text)")"#))
226+
case .token(tokenKind: let tokenKind):
227+
ArrayElementSyntax(expression: ExprSyntax(".tokenKind(.\(raw: SYNTAX_TOKEN_MAP[tokenKind]!.swiftKind))"))
228+
}
229+
}
230+
}
231+
let verifyCall = ExprSyntax("verify(layout[\(raw: index)], as: Raw\(raw: child.type.buildable).self, tokenChoices: \(choices))")
232+
ExprSyntax("assertNoError(kind, \(raw: index), \(verifyCall))")
142233
default:
143234
ExprSyntax("assertNoError(kind, \(raw: index), verify(layout[\(raw: index)], as: Raw\(raw: child.type.buildable).self))")
144235
}

0 commit comments

Comments
 (0)