Skip to content

Commit

Permalink
[Syntax] Introduce SyntaxLayout
Browse files Browse the repository at this point in the history
This replaces most use case of `keyPathInParent` and
`SyntaxNodeStructure.layout`. Since getting and comparing `KeyPath` is
not trivial, `keyPathInParent` were suffered from performance issue,

Newly introduced `SyntaxProtocol.propertyInParent` is trivial, and
comparing it with a SyntaxLayoutProperty is also trivial.
  • Loading branch information
rintaro committed Jan 21, 2025
1 parent fd232f9 commit 341f740
Show file tree
Hide file tree
Showing 35 changed files with 13,356 additions and 4,196 deletions.
13 changes: 0 additions & 13 deletions CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -376,19 +376,6 @@ public enum SyntaxNodeKind: String, CaseIterable, IdentifierConvertible, TypeCon
return "\(syntaxType)Protocol"
}

/// For base node types, generates the name of the protocol to which all
/// concrete leaf nodes that derive from this base kind should conform.
///
/// - Warning: This property can only be accessed for base node kinds; attempting to
/// access it for a non-base kind will result in a runtime error.
public var leafProtocolType: TypeSyntax {
if isBase {
return "_Leaf\(syntaxType)NodeProtocol"
} else {
fatalError("Only base kind can define leaf protocol")
}
}

/// If the syntax kind has been renamed, the previous raw value that is now
/// deprecated.
public var deprecatedRawValue: String? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ struct GenerateSwiftSyntax: AsyncParsableCommand {
),

// SwiftSyntax
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["ChildNameForKeyPath.swift"], childNameForKeyPathFile),
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["ConcreteSyntaxProperty.swift"], concreteSyntaxPropertyFile),
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["Keyword.swift"], keywordFile),
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["raw", "RawSyntaxValidation.swift"], rawSyntaxValidationFile),
GeneratedFileSpec(
Expand All @@ -128,6 +128,7 @@ struct GenerateSwiftSyntax: AsyncParsableCommand {
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxCollections.swift"], syntaxCollectionsFile),
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxEnum.swift"], syntaxEnumFile),
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxKind.swift"], syntaxKindFile),
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxLayoutPropertyName.swift"], syntaxLayoutPropertyNameFile),
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxRewriter.swift"], syntaxRewriterFile),
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxTraits.swift"], syntaxTraitsFile),
GeneratedFileSpec(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ let childNameForDiagnosticFile = SourceFileSyntax(leadingTrivia: copyrightHeader
)

try! FunctionDeclSyntax(
"private func childNameForDiagnostics(_ keyPath: AnyKeyPath) -> String?"
"private func childNameForDiagnostics(_ property: SyntaxLayoutProperty) -> String?"
) {
try! SwitchExprSyntax("switch keyPath") {
try! SwitchExprSyntax("switch property") {
for node in NON_BASE_SYNTAX_NODES.compactMap(\.layoutNode) {
for child in node.children {
if let nameForDiagnostics = child.nameForDiagnostics {
SwitchCaseSyntax("case \\\(node.type.syntaxBaseName).\(child.memberCallName):") {
SwitchCaseSyntax("case \(node.type.syntaxBaseName).layout[.\(child.memberCallName)]:") {
StmtSyntax(#"return "\#(raw: nameForDiagnostics)""#)
}
}
Expand All @@ -52,10 +52,10 @@ let childNameForDiagnosticFile = SourceFileSyntax(leadingTrivia: copyrightHeader
"""
extension SyntaxProtocol {
var childNameInParent: String? {
guard let keyPath = self.keyPathInParent else {
guard let property = self.propertyInParent else {
return nil
}
return childNameForDiagnostics(keyPath)
return childNameForDiagnostics(property)
}
}
"""
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 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 concreteSyntaxPropertyFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
DeclSyntax(
"""
extension ConcreteSyntaxProperty {
fileprivate init(_ index: Int) {
self.index = .init(index)
}
}
"""
)

for node in NON_BASE_SYNTAX_NODES {
if let layoutNode = node.layoutNode {
try! ExtensionDeclSyntax(
"\(node.apiAttributes())extension ConcreteSyntaxProperty where Base == \(node.kind.syntaxType)"
) {
for (index, child) in layoutNode.children.enumerated() {
let childType: TypeSyntax =
child.kind.isNodeChoicesEmpty
? child.syntaxNodeKind.syntaxType
: "\(node.kind.syntaxType).\(child.syntaxChoicesType)"
let type = child.isOptional ? TypeSyntax("\(childType)?") : TypeSyntax("\(childType)")
DeclSyntax(
"""
public static var \(child.varDeclName): ConcreteSyntaxProperty<\(node.kind.syntaxType), \(type)> {
.init(\(raw: index))
}
"""
)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,7 @@ let syntaxBaseNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
}
}

leafProtocolDecl(type: node.kind.leafProtocolType, inheritedType: node.kind.protocolType)
leafProtocolExtension(type: node.kind.leafProtocolType, inheritedType: node.kind.protocolType)
leafProtocolExtension(inheritedType: node.kind.protocolType)
}

try! ExtensionDeclSyntax(
Expand Down Expand Up @@ -317,27 +316,13 @@ let syntaxBaseNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
}
}

leafProtocolDecl(type: "_LeafSyntaxNodeProtocol", inheritedType: "SyntaxProtocol")
leafProtocolExtension(type: "_LeafSyntaxNodeProtocol", inheritedType: "SyntaxProtocol")
leafProtocolExtension(inheritedType: "SyntaxProtocol")
}

private func leafProtocolDecl(type: TypeSyntax, inheritedType: TypeSyntax) -> DeclSyntax {
DeclSyntax(
"""
/// Protocol that syntax nodes conform to if they don't have any semantic subtypes.
/// These are syntax nodes that are not considered base nodes for other syntax types.
///
/// Syntax nodes conforming to this protocol have their inherited casting methods
/// deprecated to prevent incorrect casting.
public protocol \(type): \(inheritedType) {}
"""
)
}

private func leafProtocolExtension(type: TypeSyntax, inheritedType: TypeSyntax) -> DeclSyntax {
DeclSyntax(
private func leafProtocolExtension( inheritedType: TypeSyntax) -> DeclSyntax {
return DeclSyntax(
#"""
extension \#(type) {
extension _LeafSyntaxNodeProtocol where Self: \#(inheritedType) {
/// Checks if the current leaf syntax node can be cast to a different specified type.
///
/// - Returns: `false` since the leaf node cannot be cast to a different specified type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ let syntaxCollectionsFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
"""
)

DeclSyntax("public static let syntaxKind = SyntaxKind.\(node.memberCallName)")
DeclSyntax("public static var syntaxKind: SyntaxKind { .\(node.enumCaseCallName) }")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ let syntaxKindFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
}
}

try VariableDeclSyntax("public var isLayout: Bool") {
try SwitchExprSyntax("switch self") {
for node in SYNTAX_NODES where node.layoutNode != nil {
SwitchCaseSyntax("case .\(node.enumCaseCallName):") {
StmtSyntax("return true")
}
}

SwitchCaseSyntax("default:") {
StmtSyntax("return false")
}
}
}

try VariableDeclSyntax("public var isMissing: Bool") {
try SwitchExprSyntax("switch self") {
for name in SyntaxNodeKind.allCases where name.isMissing {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 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 syntaxLayoutPropertyNameFile = try! SourceFileSyntax(leadingTrivia: copyrightHeader) {
try ExtensionDeclSyntax("extension SyntaxLayoutProperty") {
try VariableDeclSyntax(
"""
/// Property name if this is a valid property.
/// 'nil' if the `syntaxKind` is not a layout syntax, or the index is out of range.
@_spi(RawSyntax)
public var name: String?
"""
) {
try SwitchExprSyntax("switch (self.syntaxKind, self.index.value)") {
for node in NON_BASE_SYNTAX_NODES {
if let layoutNode = node.layoutNode {
for (index, child) in layoutNode.children.enumerated() {
SwitchCaseSyntax("case (.\(node.enumCaseCallName), \(literal: index)):") {
StmtSyntax("return \(literal: child.identifier.description)")
}
}
}
}
SwitchCaseSyntax("default: return nil")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func syntaxNode(nodesStartingWith: [Character]) -> SourceFileSyntax {
\(SwiftSyntax.Trivia(joining: [node.documentation, node.experimentalDocNote, node.grammar, node.containedIn]))\
\(node.node.apiAttributes())\
public struct \(node.kind.syntaxType): \(node.baseType.syntaxBaseName)Protocol, SyntaxHashable, \(node.base.leafProtocolType)
public struct \(node.kind.syntaxType): \(node.baseType.syntaxBaseName)Protocol, SyntaxHashable, _LayoutSyntaxNodeProtocol
"""
) {
for childNodeChoices in node.node.childrenNodeChoices() {
Expand Down Expand Up @@ -208,6 +208,12 @@ func syntaxNode(nodesStartingWith: [Character]) -> SourceFileSyntax {
}
}

// ========
// Metadata
// ========

DeclSyntax("public static var syntaxKind: SyntaxKind { .\(node.enumCaseCallName) }")

let layout = ArrayExprSyntax {
for child in node.children {
ArrayElementSyntax(
Expand Down
Loading

0 comments on commit 341f740

Please sign in to comment.