1
1
/// A regex abstract syntax tree
2
- public enum AST : ASTValue /*, ASTAction*/ {
3
- public typealias Product = Self
2
+ public indirect enum AST :
3
+ Hashable /*, _ASTPrintable ASTValue, ASTAction*/
4
+ {
5
+ /// Located value: a value wrapped with a source range
6
+ public typealias Loc = Source . Value
4
7
5
8
/// ... | ... | ...
6
- indirect case alternation( [ AST ] )
9
+ case alternation( Alternation )
7
10
8
11
/// ... ...
9
- indirect case concatenation( [ AST ] )
12
+ case concatenation( Concatenation )
10
13
11
14
/// (...)
12
- indirect case group( Group , AST )
15
+ case group( Group )
13
16
14
- indirect case quantification( Quantifier , AST )
17
+ case quantification( Quantification )
15
18
16
- case quote( String )
19
+ /// \Q...\E
20
+ case quote( Quote )
17
21
18
- case trivia // TODO: track comments
22
+ ///
23
+ case trivia( Trivia ) // TODO: track comments
19
24
20
25
case atom( Atom )
21
26
@@ -25,94 +30,116 @@ public enum AST: ASTValue/*, ASTAction*/ {
25
30
26
31
27
32
// FIXME: Move off the regex literal AST
28
- indirect case groupTransform(
29
- Group , AST , transform: CaptureTransform )
33
+ case groupTransform(
34
+ Group , transform: CaptureTransform )
30
35
}
31
36
32
- extension AST {
33
- public static var any : AST {
34
- . atom( . any)
35
- }
36
- }
37
-
38
- // Note that we're not yet an ASTEntity, would need to be a struct.
39
- // We might end up with ASTStorage which projects the nice AST type.
40
- // Values and projected entities can still refer to positions.
41
- // ASTStorage might end up becoming the ASTAction conformer
37
+ // TODO: This is currently unused, but it's likely we'll want
38
+ // to host things like global options, more source info, etc.
42
39
private struct ASTStorage {
43
40
let ast : AST
44
41
let sourceRange : SourceRange ?
45
42
}
46
43
47
44
extension AST {
48
- public var isSemantic : Bool {
45
+ // :-(
46
+ var _associatedValue : _ASTNode ? {
49
47
switch self {
50
- case . trivia: return false
51
- default : return true
48
+ case . empty: return nil
49
+ case let . alternation( v) : return v
50
+ case let . concatenation( v) : return v
51
+ case let . group( v) : return v
52
+ case let . quantification( v) : return v
53
+ case let . quote( v) : return v
54
+ case let . trivia( v) : return v
55
+ case let . atom( v) : return v
56
+ case let . customCharacterClass( v) : return v
57
+
58
+ case let . groupTransform( g, _) :
59
+ return g // FIXME: get this out of here
52
60
}
53
61
}
54
62
55
- func filter( _ f: ( AST ) -> Bool ) -> AST ? {
56
- func filt( _ children: [ AST ] ) -> [ AST ] {
57
- children. compactMap {
58
- guard f ( $0) else { return nil }
59
- return $0. filter ( f)
60
- }
63
+ /// If this node is a parent node, access its children
64
+ public var children : [ AST ] ? {
65
+ guard let av = _associatedValue else { return nil }
66
+ return ( av as? _ASTParent ) ? . children
67
+ }
68
+
69
+ /// Whether this node is "trivia" or non-semantic, like comments
70
+ public var isTrivia : Bool {
71
+ switch self {
72
+ case . trivia: return true
73
+ default : return false
61
74
}
62
- func filt( _ cc: CustomCharacterClass ) -> CustomCharacterClass {
63
- CustomCharacterClass ( cc. start, filt ( cc. members) )
75
+ }
76
+
77
+ /// Whether this node has nested somewhere inside it a capture
78
+ public var hasCapture : Bool {
79
+ if case let . group( g) = self , g. kind. value. isCapturing {
80
+ return true
64
81
}
65
- typealias CCCMember = CustomCharacterClass . Member
66
- func filt ( _ children: [ CCCMember ] ) -> [ CCCMember ] {
67
- children . compactMap {
68
- switch $0 {
69
- case let . custom ( cc ) :
70
- return . custom ( filt ( cc ) )
71
- case . range ( let lhs , let rhs ) :
72
- guard let filtLHS = f ( . atom ( lhs ) ) ? lhs : nil else { return nil }
73
- guard let filtRHS = f ( . atom ( rhs ) ) ? rhs : nil else { return nil }
74
- return . range ( filtLHS , filtRHS )
75
- case let . atom ( atom ) :
76
- return f ( . atom ( atom ) ) ? . atom ( atom ) : nil
77
- case let . setOperation ( lhsMembers , op , rhsMembers ) :
78
- return . setOperation ( filt ( lhsMembers ) , op , filt ( rhsMembers ) )
79
- }
80
- }
82
+
83
+ return self . children? . any ( \ . hasCapture ) ?? false
84
+ }
85
+ }
86
+
87
+ // MARK: - AST types
88
+
89
+ extension AST {
90
+
91
+ public struct Alternation : Hashable , _ASTNode {
92
+ public let children : [ AST ]
93
+ public let sourceRange : SourceRange
94
+
95
+ public init ( _ mems : [ AST ] , _ sourceRange : SourceRange ) {
96
+ self . children = mems
97
+ self . sourceRange = sourceRange
81
98
}
82
- switch self {
83
- case let . alternation( children) :
84
- return . alternation( filt ( children) )
85
99
86
- case let . concatenation ( children ) :
87
- return . concatenation ( filt ( children ) )
100
+ public var _dumpBase : String { " alternation " }
101
+ }
88
102
89
- case let . customCharacterClass( cc) :
90
- return . customCharacterClass( filt ( cc) )
103
+ public struct Concatenation : Hashable , _ASTNode {
104
+ public let children : [ AST ]
105
+ public let sourceRange : SourceRange
91
106
92
- case let . group( g, child) :
93
- guard let c = child. filter ( f) else { return nil }
94
- return . group( g, c)
107
+ public init ( _ mems: [ AST ] , _ sourceRange: SourceRange ) {
108
+ self . children = mems
109
+ self . sourceRange = sourceRange
110
+ }
95
111
96
- case let . groupTransform( g, child, transform) :
97
- guard let c = child. filter ( f) else { return nil }
98
- return . groupTransform( g, c, transform: transform)
112
+ public var _dumpBase : String { " " }
113
+ }
99
114
100
- case let . quantification ( q , child ) :
101
- guard let c = child . filter ( f ) else { return nil }
102
- return . quantification ( q , c )
115
+ public struct Quote : Hashable , _ASTNode {
116
+ public let literal : String
117
+ public let sourceRange : SourceRange
103
118
104
- case . any, . trivia, . quote, . atom, . empty:
105
- return f ( self ) ? self : nil
119
+ public init ( _ s: String , _ sourceRange: SourceRange ) {
120
+ self . literal = s
121
+ self . sourceRange = sourceRange
106
122
}
123
+
124
+ public var _dumpBase : String { " quote " }
107
125
}
108
126
109
- public var strippingTrivia : AST ? {
110
- filter ( \. isSemantic)
127
+ public struct Trivia : Hashable , _ASTNode {
128
+ // TODO: Contents of trivia, kinds, etc
129
+ public let sourceRange : SourceRange
130
+
131
+ public init ( _ sourceRange: SourceRange ) {
132
+ self . sourceRange = sourceRange
133
+ }
134
+
135
+ public var _dumpBase : String {
136
+ // TODO: comments, non-semantic whitespace, etc.
137
+ " "
138
+ }
111
139
}
112
140
}
113
141
114
- // FIXME: Probably remove this from the AST
115
-
142
+ // FIXME: Get this out of here
116
143
public struct CaptureTransform : Equatable , Hashable , CustomStringConvertible {
117
144
public let closure : ( Substring ) -> Any
118
145
0 commit comments