24
24
/// Results in an assertion failure if the layout is invalid.
25
25
func validateLayout( layout: RawSyntaxBuffer, as kind: SyntaxKind) {
26
26
#if DEBUG
27
- func _verify< Node: RawSyntaxNodeProtocol > ( _ raw: RawSyntax ? , as _: Node . Type , file: StaticString = #file, line: UInt = #line) {
28
- assert ( raw != nil , file: file, line: line)
29
- assert ( Node . isKindOf ( raw!) , file: file, line: line)
27
+ enum ValidationError : CustomStringConvertible {
28
+ case expectedNonNil( expectedKind: RawSyntaxNodeProtocol . Type , file: StaticString , line: UInt )
29
+ case kindMismatch( expectedKind: RawSyntaxNodeProtocol . Type , actualKind: SyntaxKind , file: StaticString , line: UInt )
30
+
31
+ var description : String {
32
+ switch self {
33
+ case . expectedNonNil( expectedKind: let expectedKind, file: _, line: _) :
34
+ return " Expected non-nil node of type \( expectedKind) but received nil "
35
+ case . kindMismatch( expectedKind: let expectedKind, actualKind: let actualKind, file: _, line: _) :
36
+ return " Expected node of type \( expectedKind) but received \( actualKind) "
37
+ }
38
+ }
39
+
40
+ var fileAndLine : ( StaticString , UInt ) {
41
+ switch self {
42
+ case . expectedNonNil( expectedKind: _, file: let file, line: let line) :
43
+ return ( file, line)
44
+ case . kindMismatch( expectedKind: _, actualKind: _, file: let file, line: let line) :
45
+ return ( file, line)
46
+ }
47
+ }
30
48
}
31
- func _verify< Node: RawSyntaxNodeProtocol > ( _ raw: RawSyntax ? , as _: Node ? . Type, file: StaticString = #file, line: UInt = #line) {
32
- raw. map { assert ( Node . isKindOf ( $0) , file: file, line: line) }
49
+
50
+ func verify< Node: RawSyntaxNodeProtocol > ( _ raw: RawSyntax ? , as _: Node . Type , file: StaticString = #file, line: UInt = #line) -> ValidationError ? {
51
+ guard let raw = raw else {
52
+ return . expectedNonNil( expectedKind: Node . self, file: file, line: line)
53
+ }
54
+ guard Node . isKindOf ( raw) else {
55
+ return . kindMismatch( expectedKind: Node . self, actualKind: raw. kind, file: file, line: line)
56
+ }
57
+ return nil
33
58
}
59
+
60
+ func verify< Node: RawSyntaxNodeProtocol > ( _ raw: RawSyntax ? , as _: Node ? . Type, file: StaticString = #file, line: UInt = #line) -> ValidationError ? {
61
+ if raw != nil {
62
+ return verify ( raw, as: Node . self, file: file, line: line)
63
+ }
64
+ return nil
65
+ }
66
+
67
+ func assertNoError( _ nodeKind: SyntaxKind , _ index: Int , _ error: ValidationError ? ) {
68
+ if let error = error {
69
+ let ( file, line) = error. fileAndLine
70
+ assertionFailure ( """
71
+ Error validating child at index \( index) of \( nodeKind) :
72
+ \( error. description)
73
+ """ , file: file, line: line)
74
+ _ = 1
75
+ }
76
+ }
77
+
78
+ func assertAnyHasNoError( _ nodeKind: SyntaxKind , _ index: Int , _ errors: [ ValidationError ? ] ) {
79
+ let nonNilErrors = errors. compactMap ( { $0 } )
80
+ if nonNilErrors. count == errors. count, let firstError = nonNilErrors. first {
81
+ let ( file, line) = firstError. fileAndLine
82
+ assertionFailure ( """
83
+ Error validating child at index \( index) of \( nodeKind) :
84
+ Node did not satisfy any node choice requirement.
85
+ Validation failures:
86
+ \( nonNilErrors. map ( { " - \( $0. description) " } ) . joined ( separator: " \n " ) )
87
+ """ , file: file, line: line)
88
+ _ = 1
89
+ }
90
+ }
91
+
34
92
switch kind {
35
93
case . unknown:
36
94
break
@@ -41,11 +99,19 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
41
99
% if node. is_buildable ( ) or node. is_missing ( ) :
42
100
assert ( layout. count == ${ len ( node. children) } )
43
101
% for ( idx, child) in enumerate ( node. children) :
44
- _verify ( layout [ ${ idx} ] , as: Raw ${ child. type_name} ${ " ? " if child. is_optional else " " }.self)
102
+ % if child. node_choices:
103
+ assertAnyHasNoError( kind, ${ idx} , [
104
+ % for node_choice in child. node_choices:
105
+ verify ( layout [ ${ idx} ] , as: Raw ${ child. type_name} ${ " ? " if child. is_optional else " " }.self)
106
+ % end
107
+ ])
108
+ % else:
109
+ assertNoError(kind, ${idx}, verify(layout[${idx}], as: Raw${child.type_name}${ " ? " if child.is_optional else " " }.self))
110
+ % end
45
111
% end
46
112
% elif node.is_syntax_collection():
47
- for element in layout {
48
- _verify( element, as: Raw${node.collection_element_type}.self)
113
+ for (index, element) in layout.enumerated() {
114
+ assertNoError(kind, index, verify( element, as: Raw${node.collection_element_type}.self) )
49
115
}
50
116
% end
51
117
break
0 commit comments