Skip to content

Commit f248906

Browse files
authored
Merge pull request #1332 from kimdv/kimdv/move-raw-syntax-validation-from-gyb-to-code-gen
2 parents 1615c39 + 9a0941b commit f248906

File tree

7 files changed

+1498
-1486
lines changed

7 files changed

+1498
-1486
lines changed

CodeGeneration/Sources/generate-swiftsyntax/GenerateSwiftSyntax.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ struct GenerateSwiftSyntax: ParsableCommand {
7373
TemplateSpec(sourceFile: keywordFile, module: swiftSyntaxDir, filename: "Keyword.swift"),
7474
TemplateSpec(sourceFile: miscFile, module: swiftSyntaxDir, filename: "Misc.swift"),
7575
TemplateSpec(sourceFile: rawSyntaxNodesFile, module: swiftSyntaxDir, filename: "raw/RawSyntaxNodes.swift"),
76+
TemplateSpec(sourceFile: rawSyntaxValidationFile, module: swiftSyntaxDir, filename: "raw/RawSyntaxValidation.swift"),
7677
TemplateSpec(sourceFile: syntaxAnyVisitorFile, module: swiftSyntaxDir, filename: "SyntaxAnyVisitor.swift"),
7778
TemplateSpec(sourceFile: syntaxBaseNodesFile, module: swiftSyntaxDir, filename: "SyntaxBaseNodes.swift"),
7879
TemplateSpec(sourceFile: syntaxCollectionsFile, module: swiftSyntaxDir, filename: "SyntaxCollections.swift"),
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 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+
import SwiftSyntax
14+
import SwiftSyntaxBuilder
15+
import SyntaxSupport
16+
import Utils
17+
18+
let rawSyntaxValidationFile = try! SourceFileSyntax(leadingTrivia: "\(generateCopyrightHeader(for: "generate-swiftsyntax"))" + .newline) {
19+
try FunctionDeclSyntax(
20+
"""
21+
/// Check that the `layout` is valid for the given 'SyntaxKind'.
22+
///
23+
/// Note that this only validates the immediate children.
24+
/// Results in an assertion failure if the layout is invalid.
25+
func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind)
26+
"""
27+
) {
28+
IfConfigDeclSyntax(
29+
clauses: IfConfigClauseListSyntax {
30+
IfConfigClauseSyntax(
31+
poundKeyword: .poundIfKeyword(),
32+
condition: ExprSyntax("DEBUG"),
33+
elements: .statements(
34+
CodeBlockItemListSyntax {
35+
DeclSyntax(
36+
#"""
37+
enum ValidationError: CustomStringConvertible {
38+
case expectedNonNil(expectedKind: RawSyntaxNodeProtocol.Type, file: StaticString, line: UInt)
39+
case kindMismatch(expectedKind: RawSyntaxNodeProtocol.Type, actualKind: SyntaxKind, file: StaticString, line: UInt)
40+
41+
var description: String {
42+
switch self {
43+
case .expectedNonNil(expectedKind: let expectedKind, file: _, line: _):
44+
return "Expected non-nil node of type \(expectedKind) but received nil"
45+
case .kindMismatch(expectedKind: let expectedKind, actualKind: let actualKind, file: _, line: _):
46+
return "Expected node of type \(expectedKind) but received \(actualKind)"
47+
}
48+
}
49+
50+
var fileAndLine: (StaticString, UInt) {
51+
switch self {
52+
case .expectedNonNil(expectedKind: _, file: let file, line: let line):
53+
return (file, line)
54+
case .kindMismatch(expectedKind: _, actualKind: _, file: let file, line: let line):
55+
return (file, line)
56+
}
57+
}
58+
}
59+
"""#
60+
)
61+
62+
DeclSyntax(
63+
"""
64+
func verify<Node: RawSyntaxNodeProtocol>(_ raw: RawSyntax?, as _: Node.Type, file: StaticString = #file, line: UInt = #line) -> ValidationError? {
65+
guard let raw = raw else {
66+
return .expectedNonNil(expectedKind: Node.self, file: file, line: line)
67+
}
68+
guard Node.isKindOf(raw) else {
69+
return .kindMismatch(expectedKind: Node.self, actualKind: raw.kind, file: file, line: line)
70+
}
71+
return nil
72+
}
73+
"""
74+
)
75+
76+
DeclSyntax(
77+
"""
78+
func verify<Node: RawSyntaxNodeProtocol>(_ raw: RawSyntax?, as _: Node?.Type, file: StaticString = #file, line: UInt = #line) -> ValidationError? {
79+
if raw != nil {
80+
return verify(raw, as: Node.self, file: file, line: line)
81+
}
82+
return nil
83+
}
84+
"""
85+
)
86+
87+
DeclSyntax(
88+
#"""
89+
func assertNoError(_ nodeKind: SyntaxKind, _ index: Int, _ error: ValidationError?) {
90+
if let error = error {
91+
let (file, line) = error.fileAndLine
92+
assertionFailure("""
93+
Error validating child at index \(index) of \(nodeKind):
94+
\(error.description)
95+
""", file: file, line: line)
96+
_ = 1
97+
}
98+
}
99+
"""#
100+
)
101+
102+
DeclSyntax(
103+
#"""
104+
func assertAnyHasNoError(_ nodeKind: SyntaxKind, _ index: Int, _ errors: [ValidationError?]) {
105+
let nonNilErrors = errors.compactMap({ $0 })
106+
if nonNilErrors.count == errors.count, let firstError = nonNilErrors.first {
107+
let (file, line) = firstError.fileAndLine
108+
assertionFailure("""
109+
Error validating child at index \(index) of \(nodeKind):
110+
Node did not satisfy any node choice requirement.
111+
Validation failures:
112+
\(nonNilErrors.map({ "- \($0.description)" }).joined(separator: "\n"))
113+
""", file: file, line: line)
114+
_ = 1
115+
}
116+
}
117+
"""#
118+
)
119+
120+
try! SwitchExprSyntax("switch kind") {
121+
SwitchCaseSyntax(
122+
"""
123+
case .token:
124+
assertionFailure("validateLayout for .token kind is not supported")
125+
"""
126+
)
127+
128+
for node in NON_BASE_SYNTAX_NODES {
129+
SwitchCaseSyntax("case .\(raw: node.swiftSyntaxKind):") {
130+
if node.isBuildable || node.isMissing {
131+
ExprSyntax("assert(layout.count == \(raw: node.children.count))")
132+
for (index, child) in node.children.enumerated() {
133+
switch child.kind {
134+
case .nodeChoices(let choices):
135+
let verifiedChoices = ArrayExprSyntax {
136+
ArrayElementSyntax(
137+
leadingTrivia: .newline,
138+
expression: ExprSyntax("verify(layout[\(raw: index)], as: Raw\(raw: child.type.buildable).self)")
139+
)
140+
}
141+
142+
ExprSyntax("assertAnyHasNoError(kind, \(raw: index), \(verifiedChoices))")
143+
default:
144+
ExprSyntax("assertNoError(kind, \(raw: index), verify(layout[\(raw: index)], as: Raw\(raw: child.type.buildable).self))")
145+
}
146+
}
147+
} else if node.isSyntaxCollection {
148+
try! ForInStmtSyntax("for (index, element) in layout.enumerated()") {
149+
if let collectionElementChoices = node.collectionElementChoices, !collectionElementChoices.isEmpty {
150+
let verifiedChoices = ArrayExprSyntax {
151+
for choiceName in node.collectionElementChoices! {
152+
let choice = SYNTAX_NODE_MAP[choiceName]!
153+
ArrayElementSyntax(
154+
leadingTrivia: .newline,
155+
expression: ExprSyntax("verify(element, as: Raw\(raw: choice.name).self)")
156+
)
157+
}
158+
}
159+
ExprSyntax("assertAnyHasNoError(kind, index, \(verifiedChoices))")
160+
} else {
161+
ExprSyntax("assertNoError(kind, index, verify(element, as: Raw\(node.collectionElementType.buildable).self))")
162+
}
163+
}
164+
}
165+
166+
BreakStmtSyntax()
167+
}
168+
}
169+
}
170+
}
171+
)
172+
)
173+
}
174+
)
175+
}
176+
}

Package.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ let package = Package(
6464
name: "SwiftSyntax",
6565
dependencies: [],
6666
exclude: [
67-
"CMakeLists.txt",
68-
"Raw/RawSyntaxValidation.swift.gyb",
67+
"CMakeLists.txt"
6968
],
7069
swiftSettings: swiftSyntaxSwiftSettings
7170
),

Sources/SwiftSyntax/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ add_swift_host_library(SwiftSyntax
3030
Raw/RawSyntaxTokenView.swift
3131

3232
generated/raw/RawSyntaxNodes.swift
33-
Raw/gyb_generated/RawSyntaxValidation.swift
33+
generated/raw/RawSyntaxValidation.swift
3434

3535
generated/Keyword.swift
3636
generated/Misc.swift

Sources/SwiftSyntax/Raw/RawSyntaxValidation.swift.gyb

Lines changed: 0 additions & 129 deletions
This file was deleted.

0 commit comments

Comments
 (0)