@@ -32,18 +32,39 @@ let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: copyrightHead
32
32
condition: ExprSyntax ( " DEBUG " ) ,
33
33
elements: . statements(
34
34
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
+
35
53
DeclSyntax (
36
54
#"""
37
55
enum ValidationError: CustomStringConvertible {
38
56
case expectedNonNil(expectedKind: RawSyntaxNodeProtocol.Type, file: StaticString, line: UInt)
39
57
case kindMismatch(expectedKind: RawSyntaxNodeProtocol.Type, actualKind: SyntaxKind, file: StaticString, line: UInt)
58
+ case tokenMismatch(expectedTokenChoices: [TokenChoice], actualKind: RawTokenKind, actualText: SyntaxText, file: StaticString, line: UInt)
40
59
41
60
var description: String {
42
61
switch self {
43
62
case .expectedNonNil(expectedKind: let expectedKind, file: _, line: _):
44
63
return "Expected non-nil node of type \(expectedKind) but received nil"
45
64
case .kindMismatch(expectedKind: let expectedKind, actualKind: let actualKind, file: _, line: _):
46
65
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)'"
47
68
}
48
69
}
49
70
@@ -53,6 +74,8 @@ let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: copyrightHead
53
74
return (file, line)
54
75
case .kindMismatch(expectedKind: _, actualKind: _, file: let file, line: let line):
55
76
return (file, line)
77
+ case .tokenMismatch(expectedTokenChoices: _, actualKind: _, actualText: _, file: let file, line: let line):
78
+ return (file, line)
56
79
}
57
80
}
58
81
}
@@ -84,6 +107,61 @@ let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: copyrightHead
84
107
"""
85
108
)
86
109
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
+
87
165
DeclSyntax (
88
166
#"""
89
167
func assertNoError(_ nodeKind: SyntaxKind, _ index: Int, _ error: ValidationError?) {
@@ -139,6 +217,19 @@ let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: copyrightHead
139
217
}
140
218
141
219
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) ) " )
142
233
default :
143
234
ExprSyntax ( " assertNoError(kind, \( raw: index) , verify(layout[ \( raw: index) ], as: Raw \( raw: child. type. buildable) .self)) " )
144
235
}
0 commit comments