2525/// Results in an assertion failure if the layout is invalid.
2626func validateLayout( layout: RawSyntaxBuffer, as kind: SyntaxKind) {
2727#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+
2842 enum ValidationError : CustomStringConvertible {
2943 case expectedNonNil( expectedKind: RawSyntaxNodeProtocol . Type , file: StaticString , line: UInt )
3044 case kindMismatch( expectedKind: RawSyntaxNodeProtocol . Type , actualKind: SyntaxKind , file: StaticString , line: UInt )
45+ case tokenMismatch( expectedTokenChoices: [ TokenChoice ] , actualKind: RawTokenBaseKind , actualText: SyntaxText , file: StaticString , line: UInt )
3146
3247 var description : String {
3348 switch self {
3449 case . expectedNonNil( expectedKind: let expectedKind, file: _, line: _) :
3550 return " Expected non-nil node of type \( expectedKind) but received nil "
3651 case . kindMismatch( expectedKind: let expectedKind, actualKind: let actualKind, file: _, line: _) :
3752 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) ' "
3855 }
3956 }
4057
@@ -44,6 +61,8 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
4461 return ( file, line)
4562 case . kindMismatch( expectedKind: _, actualKind: _, file: let file, line: let line) :
4663 return ( file, line)
64+ case . tokenMismatch( expectedTokenChoices: _, actualKind: _, actualText: _, file: let file, line: let line) :
65+ return ( file, line)
4766 }
4867 }
4968 }
@@ -65,6 +84,52 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
6584 return nil
6685 }
6786
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+
68133 func assertNoError( _ nodeKind: SyntaxKind , _ index: Int , _ error: ValidationError ? ) {
69134 if let error = error {
70135 let ( file, line) = error. fileAndLine
@@ -101,10 +166,33 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
101166% if child. node_choices:
102167 assertAnyHasNoError( kind, ${ idx} , [
103168% 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
105182% end
106183 ])
107184% 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
108196 assertNoError(kind, ${idx}, verify(layout[${idx}], as: Raw${child.type_name}${ " ? " if child.is_optional else " " }.self))
109197% end
110198% end
0 commit comments