Skip to content

Commit 78a7fa1

Browse files
committed
Add a conditional compilation flag to verify token choices
Verification of token choice is currently causing assertion failures where the list of expected token choices in the syntax tree doesn't match those the parser generates. I’d still like to get the verification code into `main` so I can conditionally enable it locally while working on the issues, so add it behind a conditional compilation flag.
1 parent 43568e9 commit 78a7fa1

File tree

2 files changed

+570
-64
lines changed

2 files changed

+570
-64
lines changed

Sources/SwiftSyntax/Raw/RawSyntaxValidation.swift.gyb

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,33 @@
2525
/// Results in an assertion failure if the layout is invalid.
2626
func 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

Comments
 (0)