25
25
/// Results in an assertion failure if the layout is invalid.
26
26
func validateLayout( layout: RawSyntaxBuffer, as kind: SyntaxKind) {
27
27
#if DEBUG
28
+ enum TokenChoice : CustomStringConvertible {
29
+ case kind( RawTokenBaseKind )
30
+ case keyword( StaticString )
31
+
32
+ var description : String {
33
+ switch self {
34
+ case . kind( let kind) :
35
+ return " \( kind) "
36
+ case . keyword( let keyword) :
37
+ return " keyword(' \( keyword) ') "
38
+ }
39
+ }
40
+ }
41
+
28
42
enum ValidationError : CustomStringConvertible {
29
43
case expectedNonNil( expectedKind: RawSyntaxNodeProtocol . Type , file: StaticString , line: UInt )
30
44
case kindMismatch( expectedKind: RawSyntaxNodeProtocol . Type , actualKind: SyntaxKind , file: StaticString , line: UInt )
45
+ case tokenMismatch( expectedTokenChoices: [ TokenChoice ] , actualKind: RawTokenBaseKind , actualText: SyntaxText , file: StaticString , line: UInt )
31
46
32
47
var description : String {
33
48
switch self {
34
49
case . expectedNonNil( expectedKind: let expectedKind, file: _, line: _) :
35
50
return " Expected non-nil node of type \( expectedKind) but received nil "
36
51
case . kindMismatch( expectedKind: let expectedKind, actualKind: let actualKind, file: _, line: _) :
37
52
return " Expected node of type \( expectedKind) but received \( actualKind) "
53
+ case . tokenMismatch( expectedTokenChoices: let tokenChoices, actualKind: let actualKind, actualText: let actualText, file: _, line: _) :
54
+ return " Expected token with one of \( tokenChoices) but received \( actualKind) with text ' \( actualText) ' "
38
55
}
39
56
}
40
57
@@ -44,6 +61,8 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
44
61
return ( file, line)
45
62
case . kindMismatch( expectedKind: _, actualKind: _, file: let file, line: let line) :
46
63
return ( file, line)
64
+ case . tokenMismatch( expectedTokenChoices: _, actualKind: _, actualText: _, file: let file, line: let line) :
65
+ return ( file, line)
47
66
}
48
67
}
49
68
}
@@ -65,6 +84,52 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
65
84
return nil
66
85
}
67
86
87
+ func verify( _ raw: RawSyntax ? , as _: RawTokenSyntax ? . Type, tokenChoices: [ TokenChoice ] , file: StaticString = #file, line: UInt = #line) -> ValidationError ? {
88
+ // Validation of token choice is currently causing assertion failures where
89
+ // the list of expected token choices in the syntax tree doesn't match those
90
+ // the parser generates. Disable the verification for now until all issues
91
+ // regarding it are fixed.
92
+ #if VALIDATE_TOKEN_CHOICES
93
+ if raw != nil {
94
+ return verify ( raw, as: RawTokenSyntax . self, tokenChoices: tokenChoices, file: file, line: line)
95
+ }
96
+ return nil
97
+ #else
98
+ return verify ( raw, as RawTokenSyntax? . self)
99
+ #endif
100
+ }
101
+
102
+ func verify( _ raw: RawSyntax ? , as _: RawTokenSyntax . Type , tokenChoices: [ TokenChoice ] , file: StaticString = #file, line: UInt = #line) -> ValidationError ? {
103
+ // Validation of token choice is currently causing assertion failures where
104
+ // the list of expected token choices in the syntax tree doesn't match those
105
+ // the parser generates. Disable the verification for now until all issues
106
+ // regarding it are fixed.
107
+ #if VALIDATE_TOKEN_CHOICES
108
+ guard let raw = raw else {
109
+ return . expectedNonNil( expectedKind: RawTokenSyntax . self, file: file, line: line)
110
+ }
111
+ if let error = verify ( raw, as: RawTokenSyntax ? . self) {
112
+ return error
113
+ }
114
+ let tokenView = raw. tokenView!
115
+ for tokenChoice in tokenChoices {
116
+ switch tokenChoice {
117
+ case . kind( let kind) :
118
+ if raw. tokenView? . rawKind. base == kind {
119
+ return nil
120
+ }
121
+ case . keyword( let keyword) :
122
+ if tokenView. rawKind. base == . keyword && tokenView. rawText == SyntaxText ( keyword) {
123
+ return nil
124
+ }
125
+ }
126
+ }
127
+ return ValidationError . tokenMismatch ( expectedTokenChoices: tokenChoices, actualKind: tokenView. rawKind. base, actualText: tokenView. rawText, file: file, line: line)
128
+ #else
129
+ return verify ( raw, as RawTokenSyntax. self)
130
+ #endif
131
+ }
132
+
68
133
func assertNoError( _ nodeKind: SyntaxKind , _ index: Int , _ error: ValidationError ? ) {
69
134
if let error = error {
70
135
let ( file, line) = error. fileAndLine
@@ -101,10 +166,33 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
101
166
% if child. node_choices:
102
167
assertAnyHasNoError( kind, ${ idx} , [
103
168
% for node_choice in child. node_choices:
104
- verify ( layout [ ${ idx} ] , as: Raw ${ child. type_name} ${ " ? " if child. is_optional else " " }.self),
169
+ % if node_choice. token_choices:
170
+ % token_choices = [ ]
171
+ % for ( token, text) in node_choice. token_choices:
172
+ % if token. name == 'Keyword' and text:
173
+ % token_choices. append ( f '. keyword ( " {text} " ) ')
174
+ % else:
175
+ % token_choices . append( ( f '. kind ( . { token. swift_kind ( ) } ) ') )
176
+ % end
177
+ % end
178
+ verify( layout [ ${ idx} ] , as: Raw ${ node_choice. type_name} ${ " ? " if child. is_optional else " " }.self, tokenChoices: [${', '.join(token_choices)}]),
179
+ % else:
180
+ verify(layout[${idx}], as: Raw${node_choice.type_name}${ " ? " if child.is_optional else " " }.self),
181
+ % end
105
182
% end
106
183
])
107
184
% else:
185
+ % if child.token_choices:
186
+ % token_choices = []
187
+ % for (token, text) in child.token_choices:
188
+ % if token.name == 'Keyword' and text:
189
+ % token_choices.append(f'.keyword( " { text} " )')
190
+ % else:
191
+ % token_choices.append((f'.kind(.{token.swift_kind()})'))
192
+ % end
193
+ % end
194
+ assertNoError(kind, ${idx}, verify(layout[${idx}], as: Raw${child.type_name}${ " ? " if child.is_optional else " " }.self, tokenChoices: [${', '.join(token_choices)}]))
195
+ % end
108
196
assertNoError(kind, ${idx}, verify(layout[${idx}], as: Raw${child.type_name}${ " ? " if child.is_optional else " " }.self))
109
197
% end
110
198
% end
0 commit comments