1313/// Represent an index in a layout.
1414public struct SyntaxLayoutIndex : Equatable , Comparable {
1515 let value : UInt32
16+
17+ @_spi ( RawSyntax)
1618 public init ( _ value: UInt32 ) {
1719 self . value = value
1820 }
21+
1922 public static func == ( lhs: Self , rhs: Self ) -> Bool {
2023 lhs. value == rhs. value
2124 }
25+
2226 public static func < ( lhs: Self , rhs: Self ) -> Bool {
2327 lhs. value < rhs. value
2428 }
@@ -27,68 +31,80 @@ public struct SyntaxLayoutIndex: Equatable, Comparable {
2731/// Represent a property in a layout syntax.
2832public struct SyntaxLayoutProperty : Equatable {
2933 /// 'SyntaxKind' of the parent layout node.
30- let baseKind : SyntaxKind
34+ let syntaxKind : SyntaxKind
3135 /// Index in the parent node layout.
3236 let index : SyntaxLayoutIndex
3337
34- public init ( baseKind: SyntaxKind , index: SyntaxLayoutIndex ) {
35- self . baseKind = baseKind
38+ @_spi ( RawSyntax)
39+ public init ( syntaxKind: SyntaxKind , index: SyntaxLayoutIndex ) {
40+ self . syntaxKind = syntaxKind
3641 self . index = index
3742 }
3843
3944 public static func == ( lhs: Self , rhs: Self ) -> Bool {
40- lhs. baseKind == rhs. baseKind && lhs. index == rhs. index
45+ lhs. syntaxKind == rhs. syntaxKind && lhs. index == rhs. index
4146 }
4247}
4348
49+ /// Protocol for concrete layout syntax nodes.
50+ public protocol _LayoutSyntaxProtocol : SyntaxProtocol {
51+ static var layout : SyntaxLayout < Self > { get }
52+ }
53+
4454/// Describes the layout of a `_LayoutSyntaxProtocol` syntax node.
4555public struct SyntaxLayout < Base: _LayoutSyntaxProtocol > {
46- let baseKind : SyntaxKind
56+ let syntaxKind : SyntaxKind
4757 let _count : UInt32
4858
4959 // SyntaxLayout can only be constructed by `_LayoutSyntaxProtocol.layout`
5060 private init ( ) { fatalError ( ) }
5161}
5262
53- #if false // Not needed at this point.
54- extension SyntaxLayout : Collection {
55- public typealias Index = SyntaxLayoutIndex
56- public typealias Element = SyntaxLayoutProperty
57-
58- public var count : Int { Int ( _count) }
59- public var startIndex : Index { Index ( 0 ) }
60- public var endIndex : Index { Index ( _count) }
61- public func index( after i: Index ) -> Index { Index ( i. value + 1 ) }
62-
63- public subscript( position: SyntaxLayoutIndex ) -> SyntaxLayoutProperty {
64- return SyntaxLayoutProperty ( baseKind: baseKind, index: position)
65- }
66- }
67- #endif
68-
69- public protocol _LayoutSyntaxProtocol : SyntaxProtocol {
70- static var layout : SyntaxLayout < Self > { get }
71- }
72-
73- public struct ConcreteSyntaxProperty < Base: SyntaxProtocol , Value> {
63+ /// Represent a typed property in a layout syntax.
64+ ///
65+ /// Specialized types have static properties to instantiate this type. E.g.:
66+ ///
67+ /// let exprProperty: ConcreteSyntaxProperty<ReturnStmtSyntax, ExprSyntax?> = .expression
68+ ///
69+ /// The property can be used similar to 'KeyPath'.
70+ ///
71+ /// let expr/*: ExprSyntax?*/ = returnStmt[property: exprProperty]
72+ /// let newReturnStmt = returnStmt.with(.expression, expr)
73+ ///
74+ public struct ConcreteSyntaxProperty < Base: _LayoutSyntaxProtocol , Value> {
7475 let index : SyntaxLayoutIndex
7576
76- // ConcreteSyntaxProperty can only be constructed by
77- // `ConcreteSyntaxProperty<Base, Value>.${name}`
77+ // ConcreteSyntaxProperty can only be constructed by `ConcreteSyntaxProperty<Base, Value>.${name}`
7878 private init ( ) { fatalError ( ) }
7979}
8080
8181extension SyntaxLayout {
82- /// Get `AnySyntaxProperty ` from `ConcreteSyntaxProperty` of the `Base` type.
82+ /// Get `AnySyntaxLayoutProperty ` from `ConcreteSyntaxProperty` of the `Base` type.
8383 /// This is convenient for comparing '.propertyInParent'. E.g.
8484 ///
8585 /// if node.propertyInParent == FunctionDeclSyntax.layout[.name] { ... }
8686 ///
8787 public subscript< T> ( property: ConcreteSyntaxProperty < Base , T > ) -> SyntaxLayoutProperty {
88- return SyntaxLayoutProperty ( baseKind : baseKind , index: property. index)
88+ return SyntaxLayoutProperty ( syntaxKind : syntaxKind , index: property. index)
8989 }
9090}
9191
92+ #if false // Not needed at this point.
93+ extension SyntaxLayout : Collection {
94+ public typealias Index = SyntaxLayoutIndex
95+ public typealias Element = SyntaxLayoutProperty
96+
97+ public var count : Int { Int ( _count) }
98+ public var startIndex : Index { Index ( 0 ) }
99+ public var endIndex : Index { Index ( _count) }
100+ public func index( after i: Index ) -> Index { Index ( i. value + 1 ) }
101+
102+ public subscript( position: SyntaxLayoutIndex ) -> SyntaxLayoutProperty {
103+ return SyntaxLayoutProperty ( syntaxKind: syntaxKind, index: position)
104+ }
105+ }
106+ #endif
107+
92108extension SyntaxProtocol {
93109 /// Return 'SyntaxLayoutProperty' in the parent node, if this node is a child
94110 /// of a layout node. 'nil' otherwise.
@@ -101,13 +117,29 @@ extension SyntaxProtocol {
101117 return nil
102118 }
103119 return SyntaxLayoutProperty (
104- baseKind : parent. kind,
120+ syntaxKind : parent. kind,
105121 index: . init( self . _syntaxNode. absoluteInfo. indexInParent)
106122 )
107123 }
124+ }
125+
126+ extension SyntaxProtocol {
127+ /// Get a property value.
128+ /// The property must be retrieved from the correct 'SyntaxLayout'
129+ public subscript( property: SyntaxLayoutProperty ) -> Syntax ? {
130+ precondition ( property. syntaxKind == Syntax ( self ) . kind)
131+ return Syntax ( self ) . child ( at: Int ( property. index. value) )
132+ }
133+
134+ /// Get a property value.
135+ public subscript< T: SyntaxProtocol > ( property: ConcreteSyntaxProperty < Self , T > ) -> T {
136+ return Syntax ( self ) . child ( at: Int ( property. index. value) ) !. cast ( T . self)
137+ }
138+ public subscript< T: SyntaxProtocol > ( property: ConcreteSyntaxProperty < Self , T ? > ) -> T ? {
139+ return Syntax ( self ) . child ( at: Int ( property. index. value) ) ? . cast ( T . self)
140+ }
108141
109- /// Returns a new syntax node that has the child at `property` replaced by
110- /// `value`.
142+ /// Returns a new syntax node that has the child at `property` replaced by `value`.
111143 public func with< T: SyntaxProtocol > ( _ property: ConcreteSyntaxProperty < Self , T > , _ value: T ) -> Self {
112144 Syntax ( self )
113145 . replacingChild ( at: Int ( property. index. value) , with: Syntax ( value) , arena: SyntaxArena ( ) )
0 commit comments