@@ -44,6 +44,7 @@ extension Regex.Match where Output == AnyRegexOutput {
44
44
anyRegexOutput. input [ range]
45
45
}
46
46
47
+ /// Access a capture by name. Returns `nil` if there's no capture with that name.
47
48
public subscript( name: String ) -> AnyRegexOutput . Element ? {
48
49
anyRegexOutput. first {
49
50
$0. name == name
@@ -54,28 +55,8 @@ extension Regex.Match where Output == AnyRegexOutput {
54
55
/// A type-erased regex output.
55
56
@available ( SwiftStdlib 5 . 7 , * )
56
57
public struct AnyRegexOutput {
57
- let input : String
58
- let _elements : [ ElementRepresentation ]
59
-
60
- /// The underlying representation of the element of a type-erased regex
61
- /// output.
62
- internal struct ElementRepresentation {
63
- /// The depth of `Optioals`s wrapping the underlying value. For example,
64
- /// `Substring` has optional depth `0`, and `Int??` has optional depth `2`.
65
- let optionalDepth : Int
66
-
67
- /// The bounds of the output element.
68
- let bounds : Range < String . Index > ?
69
-
70
- /// The name of the capture.
71
- var name : String ? = nil
72
-
73
- /// The capture reference this element refers to.
74
- var referenceID : ReferenceID ? = nil
75
-
76
- /// If the output vaule is strongly typed, then this will be set.
77
- var value : Any ? = nil
78
- }
58
+ internal let input : String
59
+ internal let _elements : [ ElementRepresentation ]
79
60
}
80
61
81
62
@available ( SwiftStdlib 5 . 7 , * )
@@ -88,80 +69,57 @@ extension AnyRegexOutput {
88
69
self = match. anyRegexOutput
89
70
}
90
71
91
- /// Returns a typed output by converting the underlying value to the specified
92
- /// type.
72
+ /// Returns a typed output by converting dynamic values to the specified type.
93
73
///
94
74
/// - Parameter type: The expected output type.
95
75
/// - Returns: The output, if the underlying value can be converted to the
96
76
/// output type; otherwise `nil`.
97
- public func `as`< Output> ( _ type: Output . Type = Output . self) -> Output ? {
77
+ public func extractValues< Output> (
78
+ as type: Output . Type = Output . self
79
+ ) -> Output ? {
98
80
let elements = map {
99
81
$0. existentialOutputComponent ( from: input [ ... ] )
100
82
}
101
83
return TypeConstruction . tuple ( of: elements) as? Output
102
84
}
103
85
}
104
86
105
- @available ( SwiftStdlib 5 . 7 , * )
106
- extension AnyRegexOutput {
107
- internal init ( input: String , elements: [ ElementRepresentation ] ) {
108
- self . init (
109
- input: input,
110
- _elements: elements
111
- )
112
- }
113
- }
114
-
115
- @available ( SwiftStdlib 5 . 7 , * )
116
- extension AnyRegexOutput . ElementRepresentation {
117
- func value( forInput input: String ) -> Any {
118
- // Ok for now because `existentialMatchComponent`
119
- // wont slice the input if there's no range to slice with
120
- //
121
- // FIXME: This is ugly :-/
122
- let input = bounds. map { input [ $0] } ?? " "
123
-
124
- return constructExistentialOutputComponent (
125
- from: input,
126
- in: bounds,
127
- value: nil ,
128
- optionalCount: optionalDepth
129
- )
130
- }
131
- }
132
-
133
87
@available ( SwiftStdlib 5 . 7 , * )
134
88
extension AnyRegexOutput : RandomAccessCollection {
89
+ /// An individual output value.
135
90
public struct Element {
136
- fileprivate let representation : ElementRepresentation
137
- let input : String
138
-
139
- var optionalDepth : Int {
140
- representation. optionalDepth
141
- }
142
-
143
- var name : String ? {
144
- representation. name
145
- }
91
+ internal let representation : ElementRepresentation
92
+ internal let input : String
146
93
147
94
/// The range over which a value was captured. `nil` for no-capture.
148
95
public var range : Range < String . Index > ? {
149
96
representation. bounds
150
97
}
151
-
152
- var referenceID : ReferenceID ? {
153
- representation. referenceID
154
- }
155
-
98
+
156
99
/// The slice of the input over which a value was captured. `nil` for no-capture.
157
100
public var substring : Substring ? {
158
101
range. map { input [ $0] }
159
102
}
160
103
161
104
/// The captured value, `nil` for no-capture
105
+ /// TODO: clarify whether this is for non-default captured values, i.e. not the
106
+ /// default Substring but more like a Date or an explicit capture
162
107
public var value : Any ? {
163
108
representation. value
164
109
}
110
+
111
+ /// The name of this capture, if it has one, otherwise `nil`.
112
+ public var name : String ? {
113
+ representation. name
114
+ }
115
+
116
+ // TODO: Consider making API, and figure out how
117
+ // DSL and this would work together...
118
+ /// Whether this capture is considered optional by the regex. I.e.,
119
+ /// whether it is inside an alternation or zero-or-n quantification.
120
+ var isOptional : Bool {
121
+ representation. optionalDepth != 0
122
+ }
165
123
}
166
124
167
125
public var startIndex : Int {
@@ -191,6 +149,8 @@ extension AnyRegexOutput: RandomAccessCollection {
191
149
192
150
@available ( SwiftStdlib 5 . 7 , * )
193
151
extension AnyRegexOutput {
152
+ /// Lookup a capture by name. Returns `nil` if no capture
153
+ /// with that name was present in the Regex.
194
154
public subscript( name: String ) -> Element ? {
195
155
first {
196
156
$0. name == name
@@ -213,16 +173,6 @@ extension Regex.Match where Output == AnyRegexOutput {
213
173
}
214
174
}
215
175
216
- @available ( SwiftStdlib 5 . 7 , * )
217
- extension Regex {
218
- /// Returns whether a named-capture with `name` exists
219
- public func contains( captureNamed name: String ) -> Bool {
220
- program. tree. root. _captureList. captures. contains ( where: {
221
- $0. name == name
222
- } )
223
- }
224
- }
225
-
226
176
@available ( SwiftStdlib 5 . 7 , * )
227
177
extension Regex where Output == AnyRegexOutput {
228
178
/// Creates a type-erased regex from an existing regex.
@@ -232,21 +182,70 @@ extension Regex where Output == AnyRegexOutput {
232
182
public init < Output> ( _ regex: Regex < Output > ) {
233
183
self . init ( node: regex. root)
234
184
}
185
+ }
235
186
236
- /// Returns a typed regex by converting the underlying types.
187
+ @available ( SwiftStdlib 5 . 7 , * )
188
+ extension Regex {
189
+ /// Creates a strongly-typed regex from a dynamic regex.
237
190
///
238
- /// - Parameter type: The expected output type.
239
- /// - Returns: A regex generic over the output type if the underlying types can be converted.
240
- /// Returns `nil` otherwise.
241
- public func `as`< Output> (
242
- _ type: Output . Type = Output . self
243
- ) -> Regex < Output > ? {
244
- let result = Regex < Output > ( node: root)
245
-
246
- guard result. _verifyType ( ) else {
191
+ /// Use this initializer to create a strongly typed regex from
192
+ /// one that was created from a string.
193
+ public init ? ( _ dynamic: Regex < AnyRegexOutput > ) {
194
+ self . init ( node: dynamic. root)
195
+ guard self . _verifyType ( ) else {
247
196
return nil
248
197
}
249
-
250
- return result
198
+ }
199
+
200
+ /// Returns whether a named-capture with `name` exists
201
+ public func contains( captureNamed name: String ) -> Bool {
202
+ program. tree. root. _captureList. captures. contains ( where: {
203
+ $0. name == name
204
+ } )
205
+ }
206
+ }
207
+
208
+ @available ( SwiftStdlib 5 . 7 , * )
209
+ extension AnyRegexOutput {
210
+ /// The underlying representation of the element of a type-erased regex
211
+ /// output.
212
+ internal struct ElementRepresentation {
213
+ /// The depth of `Optioals`s wrapping the underlying value. For example,
214
+ /// `Substring` has optional depth `0`, and `Int??` has optional depth `2`.
215
+ let optionalDepth : Int
216
+
217
+ /// The bounds of the output element.
218
+ let bounds : Range < String . Index > ?
219
+
220
+ /// The name of the capture.
221
+ var name : String ? = nil
222
+
223
+ /// The capture reference this element refers to.
224
+ var referenceID : ReferenceID ? = nil
225
+
226
+ /// If the output vaule is strongly typed, then this will be set.
227
+ var value : Any ? = nil
228
+ }
229
+
230
+ internal init ( input: String , elements: [ ElementRepresentation ] ) {
231
+ self . init ( input: input, _elements: elements)
232
+ }
233
+ }
234
+
235
+ @available ( SwiftStdlib 5 . 7 , * )
236
+ extension AnyRegexOutput . ElementRepresentation {
237
+ fileprivate func value( forInput input: String ) -> Any {
238
+ // Ok for now because `existentialMatchComponent`
239
+ // wont slice the input if there's no range to slice with
240
+ //
241
+ // FIXME: This is ugly :-/
242
+ let input = bounds. map { input [ $0] } ?? " "
243
+
244
+ return constructExistentialOutputComponent (
245
+ from: input,
246
+ in: bounds,
247
+ value: nil ,
248
+ optionalCount: optionalDepth
249
+ )
251
250
}
252
251
}
0 commit comments