Skip to content

Commit 02a0c5d

Browse files
committed
Add infrastructure for automated validation of syntax node structure
The goal here is to generalize the API inconsistency reported by @AnthonyLatsis and automatically detect them. There are valid reasons for nodes or children to violate these base rules. My idea is that we note these exceptions in expected failures, ideally with a sort explanation that motivates the deviation from standard naming rules. We aren’t running these tests at the moment yet. I’d like to merge them as a starting point for API improvement ideas at the moment. The current rules are - All nodes with base kind e.g. `ExprSyntax` should end with `ExprSyntax`. - If a child has a single keyword as its choice, it should be named `*Keyword` (e.g. `ImportKeyword`) - If a child has a single non-keyword token kind, name it the same as the the token choice (e.g. `LeftParen`) - If a token only has keyword token choices, its name should end with `Keyword`. - Children that have the same type also have the same child name. - Every node that can conform to a trait does so
1 parent a90e1be commit 02a0c5d

File tree

5 files changed

+740
-1
lines changed

5 files changed

+740
-1
lines changed

CodeGeneration/Package.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ let package = Package(
4545
"SyntaxSupport",
4646
]
4747
),
48+
.testTarget(
49+
name: "ValidateSyntaxNodes",
50+
dependencies: [
51+
"SyntaxSupport"
52+
]
53+
),
4854
]
4955
)
5056

CodeGeneration/Sources/SyntaxSupport/Child.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
/// The kind of token a node can contain. Either a token of a specific kind or a
1414
/// keyword with the given text.
15-
public enum TokenChoice {
15+
public enum TokenChoice: Equatable {
1616
case keyword(text: String)
1717
case token(tokenKind: String)
1818

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
extension Collection {
14+
/// If the collection contains a single element, return it, otherwise `nil`.
15+
var only: Element? {
16+
if !isEmpty && index(after: startIndex) == endIndex {
17+
return self.first!
18+
} else {
19+
return nil
20+
}
21+
}
22+
}
23+
24+
extension String {
25+
func dropSuffix(_ suffix: String) -> String {
26+
if hasSuffix(suffix) {
27+
return String(self.dropLast(suffix.count))
28+
} else {
29+
return self
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)