Skip to content

Commit e7c470c

Browse files
committed
Move raw syntax validation from gyb to code gen
1 parent cb8a945 commit e7c470c

File tree

6 files changed

+161
-132
lines changed

6 files changed

+161
-132
lines changed

CodeGeneration/Sources/generate-swiftsyntax/GenerateSwiftSyntax.swift

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

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)