@@ -28,6 +28,10 @@ extension Regex {
28
28
29
29
@available ( SwiftStdlib 5 . 7 , * )
30
30
extension Regex . Match {
31
+ var input : String {
32
+ anyRegexOutput. input
33
+ }
34
+
31
35
/// The output produced from the match operation.
32
36
public var output : Output {
33
37
if Output . self == AnyRegexOutput . self {
@@ -37,33 +41,48 @@ extension Regex.Match {
37
41
)
38
42
39
43
let output = AnyRegexOutput (
40
- input: anyRegexOutput . input,
44
+ input: input,
41
45
elements: [ wholeMatchCapture] + anyRegexOutput. _elements
42
46
)
43
47
44
48
return output as! Output
45
49
} else if Output . self == Substring . self {
46
50
// FIXME: Plumb whole match (`.0`) through the matching engine.
47
- return anyRegexOutput . input [ range] as! Output
48
- } else if anyRegexOutput. isEmpty, value != nil {
51
+ return input [ range] as! Output
52
+ } else if anyRegexOutput. isEmpty, let value {
49
53
// FIXME: This is a workaround for whole-match values not
50
54
// being modeled as part of captures. We might want to
51
55
// switch to a model where results are alongside captures
52
- return value! as! Output
56
+ return value as! Output
53
57
} else {
54
58
guard value == nil else {
55
59
fatalError ( " FIXME: what would this mean? " )
56
60
}
57
61
let typeErasedMatch = anyRegexOutput. existentialOutput (
58
- from: anyRegexOutput . input [ range]
62
+ from: input [ range]
59
63
)
60
64
return typeErasedMatch as! Output
61
65
}
62
66
}
63
67
68
+ var wholeMatchType : Any . Type {
69
+ value. map { type ( of: $0) } ?? Substring . self
70
+ }
71
+
64
72
/// Accesses a capture by its name or number.
65
73
public subscript< T> ( dynamicMember keyPath: KeyPath < Output , T > ) -> T {
66
- output [ keyPath: keyPath]
74
+ // Note: We should be able to get the element offset from the key path
75
+ // itself even at compile time. We need a better way of doing this.
76
+ guard let outputTupleOffset = MemoryLayout . tupleElementIndex (
77
+ of: keyPath, elementTypes: [ wholeMatchType] + anyRegexOutput. map ( \. type)
78
+ ) else {
79
+ return output [ keyPath: keyPath]
80
+ }
81
+ if outputTupleOffset == 0 {
82
+ return value. map { $0 as! T } ?? ( input [ range] as! T )
83
+ } else {
84
+ return anyRegexOutput [ outputTupleOffset - 1 ] . value as! T
85
+ }
67
86
}
68
87
69
88
/// Accesses a capture using the `.0` syntax, even when the match isn't a tuple.
@@ -83,7 +102,7 @@ extension Regex.Match {
83
102
}
84
103
85
104
return element. existentialOutputComponent (
86
- from: anyRegexOutput . input [ ... ]
105
+ from: input [ ... ]
87
106
) as! Capture
88
107
}
89
108
}
0 commit comments