Skip to content

Move raw syntax nodes from gyb to code gen #1326

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CodeGeneration/Sources/SyntaxSupport/Child.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public class Child {
case .node(kind: let kind):
return kind
case .nodeChoices:
return "syntax"
return "Syntax"
case .collection(kind: let kind, collectionElementName: _):
return kind
case .token(choices: let choices, requiresLeadingSpace: _, requiresTrailingSpace: _):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct GenerateSwiftSyntax: ParsableCommand {
// SwiftSyntax
TemplateSpec(sourceFile: keywordFile, module: swiftSyntaxDir, filename: "Keyword.swift"),
TemplateSpec(sourceFile: miscFile, module: swiftSyntaxDir, filename: "Misc.swift"),
TemplateSpec(sourceFile: rawSyntaxNodesFile, module: swiftSyntaxDir, filename: "raw/RawSyntaxNodes.swift"),
TemplateSpec(sourceFile: syntaxAnyVisitorFile, module: swiftSyntaxDir, filename: "SyntaxAnyVisitor.swift"),
TemplateSpec(sourceFile: syntaxBaseNodesFile, module: swiftSyntaxDir, filename: "SyntaxBaseNodes.swift"),
TemplateSpec(sourceFile: syntaxCollectionsFile, module: swiftSyntaxDir, filename: "SyntaxCollections.swift"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import SwiftSyntax
import SwiftSyntaxBuilder
import SyntaxSupport
import Utils

let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: "\(generateCopyrightHeader(for: "generate-swiftsyntax"))" + .newline) {
for node in SYNTAX_NODES where node.isBase {
DeclSyntax(
"""
@_spi(RawSyntax)
public protocol Raw\(raw: node.name)NodeProtocol: Raw\(raw: node.baseType.syntaxKind)NodeProtocol {}
"""
)
}

for node in SYNTAX_NODES {
try! StructDeclSyntax(
"""
@_spi(RawSyntax)
public struct Raw\(raw: node.name): Raw\(raw: (node.isBase ? node.name : node.baseType.syntaxBaseName))NodeProtocol
"""
) {
let enums: [(String, [(swiftName: String, typeName: String)])] =
node.children.compactMap { child -> (String, [(String, String)])? in
switch child.kind {
case .nodeChoices(let choices):
return (child.name, choices.map { ($0.swiftName, $0.typeName) })
default:
return nil
}
}
+ (node.collectionElementChoices?.isEmpty == false
? [("Element", node.collectionElementChoices!.map { choice -> (String, String) in (SYNTAX_NODE_MAP[choice]!.swiftSyntaxKind, SYNTAX_NODE_MAP[choice]!.name) })]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we had something like ChildKind for Node as well so we don’t need to force-unwrap here. But I think that’s something we can more easily do once we’ve gotten rid of all the gyb. In general, I feel like there’s a lot we can clean up in the SyntaxSupport module once we’re no longer tied to the Python design.

: [])

for (name, choices) in enums {
try EnumDeclSyntax(
"""
@frozen // FIXME: Not actually stable, works around a miscompile
public enum \(raw: name): RawSyntaxNodeProtocol
"""
) {
for (swiftName, typeName) in choices {
DeclSyntax("case `\(raw: swiftName)`(Raw\(raw: typeName))")
}

DeclSyntax(
"""
public static func isKindOf(_ raw: RawSyntax) -> Bool {
return \(raw: choices.map { "Raw\($0.typeName).isKindOf(raw)" }.joined(separator: " || "))
}
"""
)

try VariableDeclSyntax("public var raw: RawSyntax") {
try SwitchExprSyntax("switch self") {
for (swiftName, _) in choices {
SwitchCaseSyntax("case .\(raw: swiftName)(let node): return node.raw")
}
}
}

try InitializerDeclSyntax("public init?<T>(_ other: T) where T : RawSyntaxNodeProtocol") {
for (swiftName, typeName) in choices {
StmtSyntax(
"""
if let node = Raw\(raw: typeName)(other) {
self = .\(raw: swiftName)(node)
return
}
"""
)
}

StmtSyntax("return nil")
}
}
}

DeclSyntax(
"""
@_spi(RawSyntax)
public var layoutView: RawSyntaxLayoutView {
return raw.layoutView!
}
"""
)

try FunctionDeclSyntax("public static func isKindOf(_ raw: RawSyntax) -> Bool") {
if node.isBase {

let cases = CaseItemListSyntax {
for n in SYNTAX_NODES where n.baseKind == node.syntaxKind {
CaseItemSyntax(
pattern: ExpressionPatternSyntax(
expression: ExprSyntax(".\(raw: n.swiftSyntaxKind)")
)
)
}
}

ExprSyntax(
"""
switch raw.kind {
case \(cases): return true
default: return false
}
"""
)
} else {
StmtSyntax("return raw.kind == .\(raw: node.swiftSyntaxKind)")
}
}

DeclSyntax("public var raw: RawSyntax")

DeclSyntax(
"""
init(raw: RawSyntax) {
assert(Self.isKindOf(raw))
self.raw = raw
}
"""
)

DeclSyntax(
"""
public init?<Node: RawSyntaxNodeProtocol>(_ other: Node) {
guard Self.isKindOf(other.raw) else { return nil }
self.init(raw: other.raw)
}
"""
)

if node.isBase {
DeclSyntax(
"""
public init<Node: Raw\(raw: node.name)NodeProtocol>(_ other: Node) {
self.init(raw: other.raw)
}
"""
)
}

if node.isSyntaxCollection {
let element = node.collectionElementChoices?.isEmpty == false ? "Element" : "Raw\(node.collectionElementType.syntaxBaseName)"
DeclSyntax(
"""
public init(elements: [\(raw: element)], arena: __shared SyntaxArena) {
let raw = RawSyntax.makeLayout(
kind: .\(raw: node.swiftSyntaxKind), uninitializedCount: elements.count, arena: arena) { layout in
guard var ptr = layout.baseAddress else { return }
for elem in elements {
ptr.initialize(to: elem.raw)
ptr += 1
}
}
self.init(raw: raw)
}
"""
)

DeclSyntax(
"""
public var elements: [Raw\(raw: node.collectionElementType.syntaxBaseName)] {
layoutView.children.map { Raw\(raw: node.collectionElementType.syntaxBaseName)(raw: $0!) }
}
"""
)
}

if node.isBuildable || node.isMissing {
let params = FunctionParameterListSyntax {
for child in node.children {
FunctionParameterSyntax(
firstName: child.isUnexpectedNodes ? .wildcardToken(trailingTrivia: .space) : nil,
secondName: .identifier(child.swiftName),
colon: .colonToken(),
type: child.rawParameterType,
defaultArgument: child.isUnexpectedNodes ? child.defaultInitialization.map { InitializerClauseSyntax(value: $0) } : nil
)
}

FunctionParameterSyntax("arena: __shared SyntaxArena", for: .functionParameters)
}
try InitializerDeclSyntax("public init(\(params))") {
if !node.children.isEmpty {
let list = ExprListSyntax {
ExprSyntax("layout.initialize(repeating: nil)")
for (index, child) in node.children.enumerated() {
let optionalMark = child.isOptional ? "?" : ""
ExprSyntax("layout[\(raw: index)] = \(raw: child.swiftName)\(raw: optionalMark).raw")
.with(\.leadingTrivia, .newline)
}
}

DeclSyntax(
"""
let raw = RawSyntax.makeLayout(
kind: .\(raw: node.swiftSyntaxKind), uninitializedCount: \(raw: node.children.count), arena: arena) { layout in
\(list)
}
"""
)
} else {
DeclSyntax("let raw = RawSyntax.makeEmptyLayout(kind: .\(raw: node.swiftSyntaxKind), arena: arena)")
}
ExprSyntax("self.init(raw: raw)")
}

for (index, child) in node.children.enumerated() {
try VariableDeclSyntax("public var \(raw: child.swiftName): Raw\(raw: child.type.buildable)") {
let iuoMark = child.isOptional ? "" : "!"

if child.typeName == "Syntax" {
ExprSyntax("layoutView.children[\(raw: index)]\(raw: iuoMark)")
} else {
ExprSyntax("layoutView.children[\(raw: index)].map(Raw\(raw: child.typeName).init(raw:))\(raw: iuoMark)")
}
}
}
}
}
}
}

fileprivate extension Child {
var rawParameterType: TypeSyntax {
let paramType: String
if case ChildKind.nodeChoices = kind {
paramType = name
} else {
paramType = "Raw\(typeName)"
}

return type.optionalWrapped(type: SimpleTypeIdentifierSyntax(name: .identifier(paramType)))
}
}
1 change: 0 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ let package = Package(
dependencies: [],
exclude: [
"CMakeLists.txt",
"Raw/RawSyntaxNodes.swift.gyb",
"Raw/RawSyntaxValidation.swift.gyb",
],
swiftSettings: swiftSyntaxSwiftSettings
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftSyntax/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ add_swift_host_library(SwiftSyntax
Raw/RawSyntaxNodeProtocol.swift
Raw/RawSyntaxTokenView.swift

Raw/gyb_generated/RawSyntaxNodes.swift
generated/raw/RawSyntaxNodes.swift
Raw/gyb_generated/RawSyntaxValidation.swift

generated/Keyword.swift
Expand Down
Loading