diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index f06978c8b..f4adddd93 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -2608,28 +2608,23 @@ extension Capture { @_disfavoredOverload public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } @_disfavoredOverload public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -2638,28 +2633,23 @@ extension TryCapture { @_disfavoredOverload public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } @_disfavoredOverload public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -2687,28 +2677,23 @@ extension Capture { @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } @_disfavoredOverload public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -2717,28 +2702,23 @@ extension TryCapture { @_disfavoredOverload public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } @_disfavoredOverload public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -2760,27 +2740,22 @@ extension Capture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -2788,27 +2763,22 @@ extension Capture { extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -2833,27 +2803,22 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -2861,27 +2826,22 @@ extension Capture { extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -2903,27 +2863,22 @@ extension Capture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -2931,27 +2886,22 @@ extension Capture { extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -2976,27 +2926,22 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3004,27 +2949,22 @@ extension Capture { extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3046,27 +2986,22 @@ extension Capture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3074,27 +3009,22 @@ extension Capture { extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3119,27 +3049,22 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3147,27 +3072,22 @@ extension Capture { extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3189,27 +3109,22 @@ extension Capture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3217,27 +3132,22 @@ extension Capture { extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3262,27 +3172,22 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3290,27 +3195,22 @@ extension Capture { extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3332,27 +3232,22 @@ extension Capture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3360,27 +3255,22 @@ extension Capture { extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3405,27 +3295,22 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3433,27 +3318,22 @@ extension Capture { extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3475,27 +3355,22 @@ extension Capture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3503,27 +3378,22 @@ extension Capture { extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3548,27 +3418,22 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3576,27 +3441,22 @@ extension Capture { extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3618,27 +3478,22 @@ extension Capture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3646,27 +3501,22 @@ extension Capture { extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3691,27 +3541,22 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3719,27 +3564,22 @@ extension Capture { extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3761,27 +3601,22 @@ extension Capture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3789,27 +3624,22 @@ extension Capture { extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3834,27 +3664,22 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3862,27 +3687,22 @@ extension Capture { extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -3904,27 +3724,22 @@ extension Capture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3932,27 +3747,22 @@ extension Capture { extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -3977,27 +3787,22 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -4005,27 +3810,22 @@ extension Capture { extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -4047,27 +3847,22 @@ extension Capture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -4075,27 +3870,22 @@ extension Capture { extension TryCapture { public init( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } public init( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -4120,27 +3910,22 @@ extension Capture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -4148,27 +3933,22 @@ extension Capture { extension TryCapture { public init( @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } public init( as reference: Reference, @RegexComponentBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index 56e2f3790..b3132c5cd 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -646,28 +646,23 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) \(whereClauseTransformed) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) \(whereClauseTransformed) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -676,28 +671,23 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) \(whereClauseTransformed) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + self.init(node: .capture( + component.regex.root, + CaptureTransform(transform))) } \(disfavored)\ public init<\(genericParams), NewCapture>( _ component: R, as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) \(whereClauseTransformed) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component.regex.root))) + component.regex.root, + CaptureTransform(transform))) } } @@ -725,28 +715,23 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ public init<\(genericParams), NewCapture>( @\(concatBuilderName) _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) \(whereClauseTransformed) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } \(disfavored)\ public init<\(genericParams), NewCapture>( as reference: Reference, @\(concatBuilderName) _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture + transform: @escaping (W) throws -> NewCapture ) \(whereClauseTransformed) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } @@ -755,28 +740,23 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ public init<\(genericParams), NewCapture>( @\(concatBuilderName) _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) \(whereClauseTransformed) { - self.init(node: .capture(.transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + self.init(node: .capture( + component().regex.root, + CaptureTransform(transform))) } \(disfavored)\ public init<\(genericParams), NewCapture>( as reference: Reference, @\(concatBuilderName) _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture? + transform: @escaping (W) throws -> NewCapture? ) \(whereClauseTransformed) { self.init(node: .capture( reference: reference.id, - .transform( - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any? - }, - component().regex.root))) + component().regex.root, + CaptureTransform(transform))) } } diff --git a/Sources/_RegexParser/Regex/Parse/CaptureList.swift b/Sources/_RegexParser/Regex/Parse/CaptureList.swift index 2a5a47395..509fbf9bc 100644 --- a/Sources/_RegexParser/Regex/Parse/CaptureList.swift +++ b/Sources/_RegexParser/Regex/Parse/CaptureList.swift @@ -24,13 +24,13 @@ public struct CaptureList { extension CaptureList { public struct Capture { public var name: String? - public var type: Any.Type? + public var type: Any.Type public var optionalDepth: Int public var location: SourceLocation public init( name: String? = nil, - type: Any.Type? = nil, + type: Any.Type = Substring.self, optionalDepth: Int, _ location: SourceLocation ) { @@ -122,18 +122,15 @@ extension AST.Node { break } } - - public var _captureList: CaptureList { - var caps = CaptureList() - self._addCaptures(to: &caps, optionalNesting: 0) - return caps - } } extension AST { - /// Get the capture list for this AST + /// The capture list (including the whole match) of this AST. public var captureList: CaptureList { - root._captureList + var caps = CaptureList() + caps.append(.init(optionalDepth: 0, .fake)) + root._addCaptures(to: &caps, optionalNesting: 0) + return caps } } @@ -151,12 +148,7 @@ extension CaptureList: Equatable {} extension CaptureList.Capture: CustomStringConvertible { public var description: String { - let typeStr: String - if let ty = type { - typeStr = "\(ty)" - } else { - typeStr = "Substring" - } + let typeStr = String(describing: type) let suffix = String(repeating: "?", count: optionalDepth) return typeStr + suffix } diff --git a/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift b/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift index 6cd8001ba..3212699fb 100644 --- a/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift +++ b/Sources/_RegexParser/Regex/Parse/CaptureStructure.swift @@ -225,7 +225,7 @@ extension CaptureStructure: CustomStringConvertible { extension AST { /// The capture structure of this AST for compiler communication. var captureStructure: CaptureStructure { - root._captureList._captureStructure(nestOptionals: true) + captureList._captureStructure(nestOptionals: true) } } @@ -246,10 +246,7 @@ extension CaptureList { extension CaptureList.Capture { func _captureStructure(nestOptionals: Bool) -> CaptureStructure { if optionalDepth == 0 { - if let ty = type { - return .atom(name: name, type: .init(ty)) - } - return .atom(name: name) + return .atom(name: name, type: type == Substring.self ? nil : .init(type)) } var copy = self copy.optionalDepth = 0 diff --git a/Sources/_RegexParser/Regex/Parse/Sema.swift b/Sources/_RegexParser/Regex/Parse/Sema.swift index 83c014d2a..b7d2bfd6f 100644 --- a/Sources/_RegexParser/Regex/Parse/Sema.swift +++ b/Sources/_RegexParser/Regex/Parse/Sema.swift @@ -77,7 +77,7 @@ extension RegexValidator { } switch ref.kind { case .absolute(let i): - guard i <= captures.captures.count else { + guard i < captures.captures.count else { throw error(.invalidReference(i), at: ref.innerLoc) } case .named(let name): diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index 3a91b6c67..f4de2f782 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -4,32 +4,44 @@ extension Compiler { struct ByteCodeGen { var options: MatchingOptions var builder = Program.Builder() + /// A Boolean indicating whether the first matchable atom has been emitted. + /// This is used to determine whether to apply initial options. + var hasEmittedFirstMatchableAtom = false init(options: MatchingOptions, captureList: CaptureList) { self.options = options self.builder.captureList = captureList } - - mutating func finish( - ) throws -> Program { - builder.buildAccept() - return try builder.assemble() - } } } extension Compiler.ByteCodeGen { + mutating func emitRoot(_ root: DSLTree.Node) throws -> Program { + // The whole match (`.0` element of output) is equivalent to an implicit + // capture over the entire regex. + try emitNode(.capture(name: nil, reference: nil, root)) + builder.buildAccept() + return try builder.assemble() + } +} + +fileprivate extension Compiler.ByteCodeGen { mutating func emitAtom(_ a: DSLTree.Atom) throws { + defer { + if a.isMatchable { + hasEmittedFirstMatchableAtom = true + } + } switch a { case .any: emitAny() case let .char(c): try emitCharacter(c) - + case let .scalar(s): try emitScalar(s) - + case let .assertion(kind): try emitAssertion(kind.ast) @@ -40,7 +52,7 @@ extension Compiler.ByteCodeGen { builder.buildUnresolvedReference(id: id) case let .changeMatchingOptions(optionSequence): - if !builder.hasReceivedInstructions { + if !hasEmittedFirstMatchableAtom { builder.initialOptions.apply(optionSequence.ast) } options.apply(optionSequence.ast) @@ -65,8 +77,7 @@ extension Compiler.ByteCodeGen { switch ref.kind { case .absolute(let i): - // Backreferences number starting at 1 - builder.buildBackreference(.init(i-1)) + builder.buildBackreference(.init(i)) case .named(let name): try builder.buildNamedReference(name) case .relative: @@ -329,9 +340,8 @@ extension Compiler.ByteCodeGen { } mutating func emitMatcher( - _ matcher: @escaping _MatcherInterface, - into capture: CaptureRegister? = nil - ) { + _ matcher: @escaping _MatcherInterface + ) -> ValueRegister { // TODO: Consider emitting consumer interface if // not captured. This may mean we should store @@ -343,26 +353,7 @@ extension Compiler.ByteCodeGen { let valReg = builder.makeValueRegister() builder.buildMatcher(matcher, into: valReg) - - // TODO: Instruction to store directly - if let cap = capture { - builder.buildMove(valReg, into: cap) - } - } - - mutating func emitTransform( - _ t: CaptureTransform, - _ child: DSLTree.Node, - into cap: CaptureRegister - ) throws { - let transform = builder.makeTransformFunction { - input, range in - try t(input[range]) - } - builder.buildBeginCapture(cap) - try emitNode(child) - builder.buildEndCapture(cap) - builder.buildTransformCapture(cap, transform) + return valReg } mutating func emitNoncapturingGroup( @@ -388,7 +379,7 @@ extension Compiler.ByteCodeGen { throw Unreachable("These should produce a capture node") case .changeMatchingOptions(let optionSequence): - if !builder.hasReceivedInstructions { + if !hasEmittedFirstMatchableAtom { builder.initialOptions.apply(optionSequence) } options.apply(optionSequence) @@ -612,7 +603,8 @@ extension Compiler.ByteCodeGen { builder.buildConsume(by: consumer) } - mutating func emitNode(_ node: DSLTree.Node) throws { + @discardableResult + mutating func emitNode(_ node: DSLTree.Node) throws -> ValueRegister? { switch node { case let .orderedChoice(children): @@ -623,20 +615,34 @@ extension Compiler.ByteCodeGen { try emitConcatenationComponent(child) } - case let .capture(name, refId, child): + case let .capture(name, refId, child, transform): options.beginScope() defer { options.endScope() } let cap = builder.makeCapture(id: refId, name: name) - switch child { - case let .matcher(_, m): - emitMatcher(m, into: cap) - case let .transform(t, child): - try emitTransform(t, child, into: cap) - default: - builder.buildBeginCapture(cap) - try emitNode(child) - builder.buildEndCapture(cap) + builder.buildBeginCapture(cap) + let value = try emitNode(child) + builder.buildEndCapture(cap) + // If the child node produced a custom capture value, e.g. the result of + // a matcher, this should override the captured substring. + if let value { + builder.buildMove(value, into: cap) + } + // If there's a capture transform, apply it now. + if let transform = transform { + let fn = builder.makeTransformFunction { input, storedCapture in + // If it's a substring capture with no custom value, apply the + // transform directly to the substring to avoid existential traffic. + if let cap = storedCapture.latest, cap.value == nil { + return try transform(input[cap.range]) + } + let value = constructExistentialOutputComponent( + from: input, + component: storedCapture.latest, + optionalCount: 0) + return try transform(value) + } + builder.buildTransformCapture(cap, fn) } case let .nonCapturingGroup(kind, child): @@ -704,10 +710,10 @@ extension Compiler.ByteCodeGen { } case let .regexLiteral(l): - try emitNode(l.ast.dslTreeNode) + return try emitNode(l.ast.dslTreeNode) case let .convertedRegexLiteral(n, _): - try emitNode(n) + return try emitNode(n) case .absentFunction: throw Unsupported("absent function") @@ -715,18 +721,14 @@ extension Compiler.ByteCodeGen { throw Unsupported("consumer") case let .matcher(_, f): - emitMatcher(f) - - case .transform: - throw Unreachable( - "Transforms only directly inside captures") + return emitMatcher(f) case .characterPredicate: throw Unsupported("character predicates") case .trivia, .empty: - return + return nil } + return nil } } - diff --git a/Sources/_StringProcessing/Capture.swift b/Sources/_StringProcessing/Capture.swift index 6f87fa625..a8d663651 100644 --- a/Sources/_StringProcessing/Capture.swift +++ b/Sources/_StringProcessing/Capture.swift @@ -13,18 +13,14 @@ // TODO: Where should this live? Inside TypeConstruction? func constructExistentialOutputComponent( - from input: Substring, - in range: Range?, - value: Any?, + from input: String, + component: (range: Range, value: Any?)?, optionalCount: Int ) -> Any { let someCount: Int var underlying: Any - if let v = value { - underlying = v - someCount = optionalCount - } else if let r = range { - underlying = input[r] + if let component = component { + underlying = component.value ?? input[component.range] someCount = optionalCount } else { // Ok since we Any-box every step up the ladder @@ -43,12 +39,11 @@ func constructExistentialOutputComponent( @available(SwiftStdlib 5.7, *) extension AnyRegexOutput.Element { func existentialOutputComponent( - from input: Substring + from input: String ) -> Any { constructExistentialOutputComponent( from: input, - in: range, - value: value, + component: representation.content, optionalCount: representation.optionalDepth ) } @@ -64,15 +59,13 @@ extension Sequence where Element == AnyRegexOutput.Element { // FIXME: This is a stop gap where we still slice the input // and traffic through existentials @available(SwiftStdlib 5.7, *) - func existentialOutput( - from input: Substring - ) -> Any { - var caps = Array() - caps.append(input) - caps.append(contentsOf: self.map { + func existentialOutput(from input: String) -> Any { + let elements = map { $0.existentialOutputComponent(from: input) - }) - return TypeConstruction.tuple(of: caps) + } + return elements.count == 1 + ? elements[0] + : TypeConstruction.tuple(of: elements) } func slices(from input: String) -> [Substring?] { diff --git a/Sources/_StringProcessing/Compiler.swift b/Sources/_StringProcessing/Compiler.swift index 4d97c5758..601cd52a4 100644 --- a/Sources/_StringProcessing/Compiler.swift +++ b/Sources/_StringProcessing/Compiler.swift @@ -28,11 +28,9 @@ class Compiler { __consuming func emit() throws -> Program { // TODO: Handle global options var codegen = ByteCodeGen( - options: options, captureList: tree.root._captureList + options: options, captureList: tree.captureList ) - try codegen.emitNode(tree.root) - let program = try codegen.finish() - return program + return try codegen.emitRoot(tree.root) } } diff --git a/Sources/_StringProcessing/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index 640fe3c93..a912fd136 100644 --- a/Sources/_StringProcessing/ConsumerInterface.swift +++ b/Sources/_StringProcessing/ConsumerInterface.swift @@ -45,8 +45,6 @@ extension DSLTree.Node { fatalError("FIXME: Is this where we handle them?") case .matcher: fatalError("FIXME: Is this where we handle them?") - case .transform: - fatalError("FIXME: Is this where we handle them?") case .characterPredicate: fatalError("FIXME: Is this where we handle them?") } diff --git a/Sources/_StringProcessing/Engine/MEBuilder.swift b/Sources/_StringProcessing/Engine/MEBuilder.swift index f706c0471..917e010f6 100644 --- a/Sources/_StringProcessing/Engine/MEBuilder.swift +++ b/Sources/_StringProcessing/Engine/MEBuilder.swift @@ -78,11 +78,6 @@ extension MEProgram.Builder { var lastInstructionAddress: InstructionAddress { .init(instructions.endIndex - 1) } - - /// `true` if the builder has received any instructions. - var hasReceivedInstructions: Bool { - !instructions.isEmpty - } mutating func buildNop(_ r: StringRegister? = nil) { instructions.append(.init(.nop, .init(optionalString: r))) diff --git a/Sources/_StringProcessing/Engine/MECapture.swift b/Sources/_StringProcessing/Engine/MECapture.swift index 7003c0261..054612e71 100644 --- a/Sources/_StringProcessing/Engine/MECapture.swift +++ b/Sources/_StringProcessing/Engine/MECapture.swift @@ -45,46 +45,25 @@ extension Processor { // By remembering the entire history, we waste space, but // we get flexibility for now. // - fileprivate var stack: Array> = [] - - // Also save entire history of captured values -_- - // - // We will need to really zoom in on performance here... - fileprivate var valueStack: Array = [] + fileprivate var history: Array<(range: Range, value: Any?)> = [] // An in-progress capture start fileprivate var currentCaptureBegin: Position? = nil fileprivate func _invariantCheck() { if startState == nil { - assert(stack.isEmpty) - assert(valueStack.isEmpty) + assert(history.isEmpty) assert(currentCaptureBegin == nil) } else if currentCaptureBegin == nil { - assert(!stack.isEmpty || !valueStack.isEmpty) - } - if hasValues { - // FIXME: how? - // assert(valueStack.count == stack.count) + assert(!history.isEmpty) } } // MARK: - IPI - var isEmpty: Bool { stack.isEmpty } - - var hasValues: Bool { !valueStack.isEmpty } - - var history: Array> { - stack - } - var valueHistory: Array { - valueStack - } - - var latest: Range? { stack.last } + var isEmpty: Bool { history.isEmpty } - var latestValue: Any? { valueStack.last } + var latest: (range: Range, value: Any?)? { history.last } /// Start a new capture. If the previously started one was un-ended, /// will clear it and restart. If this is the first start, will save `initial`. @@ -105,7 +84,7 @@ extension Processor { assert(currentCaptureBegin != nil) defer { _invariantCheck() } - stack.append(currentCaptureBegin! ..< idx) + history.append((currentCaptureBegin! ..< idx, value: nil)) } mutating func registerValue( @@ -117,16 +96,16 @@ extension Processor { if let sp = overwriteInitial { self.startState = sp } - valueStack.append(value) + history[history.endIndex - 1].value = value } mutating func fail(truncatingAt stackIdx: Int) { _invariantCheck() - assert(stackIdx <= stack.endIndex) + assert(stackIdx <= history.endIndex) defer { _invariantCheck() } - stack.removeSubrange(stackIdx...) - if stack.isEmpty { + history.removeSubrange(stackIdx...) + if history.isEmpty { startState = nil } } @@ -135,9 +114,6 @@ extension Processor { extension Processor._StoredCapture: CustomStringConvertible { var description: String { - if hasValues { - return String(describing: valueStack) - } return String(describing: history) } } @@ -146,16 +122,12 @@ struct MECaptureList { var values: Array._StoredCapture> var referencedCaptureOffsets: [ReferenceID: Int] -// func extract(from s: String) -> Array> { -// caps.map { $0.map { s[$0] } } -// } -// - func latestUntyped(from s: String) -> Array { + func latestUntyped(from input: String) -> Array { values.map { guard let last = $0.latest else { return nil } - return s[last] + return input[last.0] } } } diff --git a/Sources/_StringProcessing/Engine/MEProgram.swift b/Sources/_StringProcessing/Engine/MEProgram.swift index 8b4737e7a..52aef1511 100644 --- a/Sources/_StringProcessing/Engine/MEProgram.swift +++ b/Sources/_StringProcessing/Engine/MEProgram.swift @@ -11,12 +11,12 @@ @_implementationOnly import _RegexParser -struct MEProgram where Input.Element: Equatable { +struct MEProgram where Input.Element: Equatable { typealias ConsumeFunction = (Input, Range) -> Input.Index? typealias AssertionFunction = (Input, Input.Index, Range) throws -> Bool typealias TransformFunction = - (Input, Range) throws -> Any? + (Input, Processor._StoredCapture) throws -> Any? typealias MatcherFunction = (Input, Input.Index, Range) throws -> (Input.Index, Any)? diff --git a/Sources/_StringProcessing/Engine/Processor.swift b/Sources/_StringProcessing/Engine/Processor.swift index 8f777ad33..406d2cc8c 100644 --- a/Sources/_StringProcessing/Engine/Processor.swift +++ b/Sources/_StringProcessing/Engine/Processor.swift @@ -419,7 +419,7 @@ extension Processor { // Should we assert it's not finished yet? // What's the behavior there? let cap = storedCaptures[capNum] - guard let range = cap.latest else { + guard let range = cap.latest?.range else { signalFailure() return } @@ -446,13 +446,9 @@ extension Processor { let transform = registers[trans] let capNum = Int(asserting: cap.rawValue) - guard let range = storedCaptures[capNum].latest else { - fatalError( - "Unreachable: transforming without a capture") - } do { // FIXME: Pass input or the slice? - guard let value = try transform(input, range) else { + guard let value = try transform(input, storedCaptures[capNum]) else { signalFailure() return } diff --git a/Sources/_StringProcessing/Engine/Registers.swift b/Sources/_StringProcessing/Engine/Registers.swift index bc17f1215..812866ee6 100644 --- a/Sources/_StringProcessing/Engine/Registers.swift +++ b/Sources/_StringProcessing/Engine/Registers.swift @@ -177,7 +177,6 @@ extension MEProgram { var positionStackAddresses = 0 var savePointAddresses = 0 var captures = 0 - } } diff --git a/Sources/_StringProcessing/Engine/Structuralize.swift b/Sources/_StringProcessing/Engine/Structuralize.swift index 129ac1677..e2d7f3ff0 100644 --- a/Sources/_StringProcessing/Engine/Structuralize.swift +++ b/Sources/_StringProcessing/Engine/Structuralize.swift @@ -3,8 +3,7 @@ extension CaptureList { @available(SwiftStdlib 5.7, *) func createElements( - _ list: MECaptureList, - _ input: String + _ list: MECaptureList ) -> [AnyRegexOutput.ElementRepresentation] { assert(list.values.count == captures.count) @@ -13,10 +12,9 @@ extension CaptureList { for (i, (cap, meStored)) in zip(captures, list.values).enumerated() { let element = AnyRegexOutput.ElementRepresentation( optionalDepth: cap.optionalDepth, - bounds: meStored.latest, + content: meStored.latest, name: cap.name, - referenceID: list.referencedCaptureOffsets.first { $1 == i }?.key, - value: meStored.latestValue + referenceID: list.referencedCaptureOffsets.first { $1 == i }?.key ) result.append(element) diff --git a/Sources/_StringProcessing/Executor.swift b/Sources/_StringProcessing/Executor.swift index 4f428cf06..941d5943a 100644 --- a/Sources/_StringProcessing/Executor.swift +++ b/Sources/_StringProcessing/Executor.swift @@ -40,31 +40,10 @@ struct Executor { referencedCaptureOffsets: engine.program.referencedCaptureOffsets) let range = inputRange.lowerBound.. Output? { let elements = map { - $0.existentialOutputComponent(from: input[...]) + $0.existentialOutputComponent(from: input) } return TypeConstruction.tuple(of: elements) as? Output } @@ -52,7 +52,7 @@ extension AnyRegexOutput: RandomAccessCollection { /// The range over which a value was captured. `nil` for no-capture. public var range: Range? { - representation.bounds + representation.content?.range } /// The slice of the input over which a value was captured. `nil` for no-capture. @@ -60,12 +60,12 @@ extension AnyRegexOutput: RandomAccessCollection { range.map { input[$0] } } - /// The captured value, `nil` for no-capture + /// The captured value, `nil` for no-capture. public var value: Any? { - representation.value ?? substring + representation.value(forInput: input) } - internal var type: Any.Type { + public var type: Any.Type { representation.type } @@ -168,7 +168,7 @@ extension Regex { /// Returns whether a named-capture with `name` exists public func contains(captureNamed name: String) -> Bool { - program.tree.root._captureList.captures.contains(where: { + program.tree.captureList.captures.contains(where: { $0.name == name }) } @@ -196,8 +196,7 @@ extension Regex.Match where Output == AnyRegexOutput { public init(_ match: Regex.Match) { self.init( anyRegexOutput: match.anyRegexOutput, - range: match.range, - value: match.value + range: match.range ) } } @@ -231,17 +230,15 @@ extension AnyRegexOutput { /// `Substring` has optional depth `0`, and `Int??` has optional depth `2`. let optionalDepth: Int - /// The bounds of the output element. - let bounds: Range? + /// The capture content representation, i.e. the element bounds and the + /// value (if available). + let content: (range: Range, value: Any?)? /// The name of the capture. var name: String? = nil /// The capture reference this element refers to. var referenceID: ReferenceID? = nil - - /// If the output vaule is strongly typed, then this will be set. - var value: Any? = nil } internal init(input: String, elements: [ElementRepresentation]) { @@ -252,22 +249,15 @@ extension AnyRegexOutput { @available(SwiftStdlib 5.7, *) extension AnyRegexOutput.ElementRepresentation { fileprivate func value(forInput input: String) -> Any { - // Ok for now because `existentialMatchComponent` - // wont slice the input if there's no range to slice with - // - // FIXME: This is ugly :-/ - let input = bounds.map { input[$0] } ?? "" - - return constructExistentialOutputComponent( + constructExistentialOutputComponent( from: input, - in: bounds, - value: nil, + component: content, optionalCount: optionalDepth ) } var type: Any.Type { - value.map { Swift.type(of: $0) } + content?.value.map { Swift.type(of: $0) } ?? TypeConstruction.optionalType(of: Substring.self, depth: optionalDepth) } } diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index c3842a7b9..2d7562adf 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -37,7 +37,8 @@ extension DSLTree { /// /// (...), (?...) case capture( - name: String? = nil, reference: ReferenceID? = nil, Node) + name: String? = nil, reference: ReferenceID? = nil, Node, + CaptureTransform? = nil) /// Matches a noncapturing subpattern. case nonCapturingGroup(_AST.GroupKind, Node) @@ -88,9 +89,6 @@ extension DSLTree { // MARK: - Extensibility points - /// Transform a range into a value, most often used inside captures - case transform(CaptureTransform, Node) - case consumer(_ConsumerInterface) case matcher(Any.Type, _MatcherInterface) @@ -254,7 +252,7 @@ public typealias _CharacterPredicateInterface = ( extension DSLTree.Node { @_spi(RegexBuilder) - public var children: [DSLTree.Node]? { + public var children: [DSLTree.Node] { switch self { case let .orderedChoice(v): return v @@ -264,9 +262,8 @@ extension DSLTree.Node { // Treat this transparently return n.children - case let .capture(_, _, n): return [n] + case let .capture(_, _, n, _): return [n] case let .nonCapturingGroup(_, n): return [n] - case let .transform(_, n): return [n] case let .quantification(_, _, n): return [n] case let .conditional(_, t, f): return [t,f] @@ -336,20 +333,7 @@ extension DSLTree.Node { return n.hasCapture default: - return self.children?.any(\.hasCapture) ?? false - } - } -} - -extension DSLTree.Node { - /// For typed capture-producing nodes, the type produced. - var valueCaptureType: AnyType? { - switch self { - case let .matcher(t, _): - return AnyType(t) - case let .transform(t, _): - return AnyType(t.resultType) - default: return nil + return self.children.any(\.hasCapture) } } } @@ -387,40 +371,80 @@ public struct ReferenceID: Hashable, Sendable { @_spi(RegexBuilder) public struct CaptureTransform: Hashable, CustomStringConvertible, Sendable { - public enum Closure: Sendable { - case failable(@Sendable (Substring) throws -> Any?) - case nonfailable(@Sendable (Substring) throws -> Any) + enum Closure: Sendable { + /// A failable transform. + case failable((Any) throws -> Any?) + /// Specialized case of `failable` for performance. + case substringFailable((Substring) throws -> Any?) + /// A non-failable transform. + case nonfailable((Any) throws -> Any) + /// Specialized case of `failable` for performance. + case substringNonfailable((Substring) throws -> Any?) } - public let resultType: Any.Type - public let closure: Closure + let argumentType: Any.Type + let resultType: Any.Type + let closure: Closure - public init(resultType: Any.Type, closure: Closure) { + init(argumentType: Any.Type, resultType: Any.Type, closure: Closure) { + self.argumentType = argumentType self.resultType = resultType self.closure = closure } - public init( - resultType: Any.Type, - _ closure: @Sendable @escaping (Substring) throws -> Any + public init( + _ userSpecifiedTransform: @escaping (Argument) throws -> Result ) { - self.init(resultType: resultType, closure: .nonfailable(closure)) + let closure: Closure + if let substringTransform = userSpecifiedTransform + as? (Substring) throws -> Result { + closure = .substringNonfailable(substringTransform) + } else { + closure = .nonfailable { + try userSpecifiedTransform($0 as! Argument) as Any + } + } + self.init( + argumentType: Argument.self, + resultType: Result.self, + closure: closure) } - public init( - resultType: Any.Type, - _ closure: @Sendable @escaping (Substring) throws -> Any? + public init( + _ userSpecifiedTransform: @escaping (Argument) throws -> Result? ) { - self.init(resultType: resultType, closure: .failable(closure)) + let closure: Closure + if let substringTransform = userSpecifiedTransform + as? (Substring) throws -> Result? { + closure = .substringFailable(substringTransform) + } else { + closure = .failable { + try userSpecifiedTransform($0 as! Argument) as Any? + } + } + self.init( + argumentType: Argument.self, + resultType: Result.self, + closure: closure) } - public func callAsFunction(_ input: Substring) throws -> Any? { + func callAsFunction(_ input: Any) throws -> Any? { switch closure { - case .nonfailable(let closure): - let result = try closure(input) + case .nonfailable(let transform): + let result = try transform(input) assert(type(of: result) == resultType) return result - case .failable(let closure): - guard let result = try closure(input) else { + case .substringNonfailable(let transform): + let result = try transform(input as! Substring) + assert(type(of: result) == resultType) + return result + case .failable(let transform): + guard let result = try transform(input) else { + return nil + } + assert(type(of: result) == resultType) + return result + case .substringFailable(let transform): + guard let result = try transform(input as! Substring) else { return nil } assert(type(of: result) == resultType) @@ -428,6 +452,19 @@ public struct CaptureTransform: Hashable, CustomStringConvertible, Sendable { } } + func callAsFunction(_ input: Substring) throws -> Any? { + switch closure { + case .substringFailable(let transform): + return try transform(input) + case .substringNonfailable(let transform): + return try transform(input) + case .failable(let transform): + return try transform(input) + case .nonfailable(let transform): + return try transform(input) + } + } + public static func == (lhs: CaptureTransform, rhs: CaptureTransform) -> Bool { unsafeBitCast(lhs.closure, to: (Int, Int).self) == unsafeBitCast(rhs.closure, to: (Int, Int).self) @@ -440,7 +477,7 @@ public struct CaptureTransform: Hashable, CustomStringConvertible, Sendable { } public var description: String { - "" + "" } } @@ -466,10 +503,10 @@ extension DSLTree.Node { child._addCaptures(to: &list, optionalNesting: nesting) } - case let .capture(name, _, child): + case let .capture(name, _, child, transform): list.append(.init( name: name, - type: child.valueCaptureType?.base, + type: transform?.resultType ?? child.wholeMatchType, optionalDepth: nesting, .fake)) child._addCaptures(to: &list, optionalNesting: nesting) @@ -513,23 +550,54 @@ extension DSLTree.Node { case .matcher: break - case .transform(_, let child): - child._addCaptures(to: &list, optionalNesting: nesting) - case .customCharacterClass, .atom, .trivia, .empty, .quotedLiteral, .consumer, .characterPredicate: break } } - var _captureList: CaptureList { - var list = CaptureList() - self._addCaptures(to: &list, optionalNesting: 0) - return list + /// Returns true if the node is output-forwarding, i.e. not defining its own + /// output but forwarding its only child's output. + var isOutputForwarding: Bool { + switch self { + case .nonCapturingGroup: + return true + case .orderedChoice, .concatenation, .capture, + .conditional, .quantification, .customCharacterClass, .atom, + .trivia, .empty, .quotedLiteral, .regexLiteral, .absentFunction, + .convertedRegexLiteral, .consumer, + .characterPredicate, .matcher: + return false + } + } + + /// Returns the output-defining node, peering through any output-forwarding + /// nodes. + var outputDefiningNode: Self { + if isOutputForwarding { + assert(children.count == 1) + return children[0].outputDefiningNode + } + return self + } + + /// Returns the type of the whole match, i.e. `.0` element type of the output. + var wholeMatchType: Any.Type { + if case .matcher(let type, _) = outputDefiningNode { + return type + } + return Substring.self } } extension DSLTree { + var captureList: CaptureList { + var list = CaptureList() + list.append(.init(type: root.wholeMatchType, optionalDepth: 0, .fake)) + root._addCaptures(to: &list, optionalNesting: 0) + return list + } + /// Presents a wrapped version of `DSLTree.Node` that can provide an internal /// `_TreeNode` conformance. struct _Tree: _TreeNode { @@ -549,9 +617,8 @@ extension DSLTree { // Treat this transparently return _Tree(n).children - case let .capture(_, _, n): return [_Tree(n)] + case let .capture(_, _, n, _): return [_Tree(n)] case let .nonCapturingGroup(_, n): return [_Tree(n)] - case let .transform(_, n): return [_Tree(n)] case let .quantification(_, _, n): return [_Tree(n)] case let .conditional(_, t, f): return [_Tree(t), _Tree(f)] @@ -691,3 +758,17 @@ extension DSLTree { } } } + +extension DSLTree.Atom { + /// Returns a Boolean indicating whether the atom represents a pattern that's + /// matchable, e.g. a character or a scalar, not representing a change of + /// matching options or an assertion. + var isMatchable: Bool { + switch self { + case .changeMatchingOptions, .assertion: + return false + case .char, .scalar, .any, .backreference, .symbolicReference, .unconverted: + return true + } + } +} diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 331057b9e..831c758dd 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -21,8 +21,6 @@ extension Regex { /// The range of the overall match. public let range: Range - - let value: Any? } } @@ -35,38 +33,12 @@ extension Regex.Match { /// The output produced from the match operation. public var output: Output { if Output.self == AnyRegexOutput.self { - let wholeMatchCapture = AnyRegexOutput.ElementRepresentation( - optionalDepth: 0, - bounds: range - ) - - let output = AnyRegexOutput( - input: input, - elements: [wholeMatchCapture] + anyRegexOutput._elements - ) - - return output as! Output - } else if Output.self == Substring.self { - // FIXME: Plumb whole match (`.0`) through the matching engine. - return input[range] as! Output - } else if anyRegexOutput.isEmpty, let value { - // FIXME: This is a workaround for whole-match values not - // being modeled as part of captures. We might want to - // switch to a model where results are alongside captures - return value as! Output - } else { - guard value == nil else { - fatalError("FIXME: what would this mean?") - } - let typeErasedMatch = anyRegexOutput.existentialOutput( - from: input[range] - ) - return typeErasedMatch as! Output + return anyRegexOutput as! Output } - } - - var wholeMatchType: Any.Type { - value.map { type(of: $0) } ?? Substring.self + let typeErasedMatch = anyRegexOutput.existentialOutput( + from: anyRegexOutput.input + ) + return typeErasedMatch as! Output } /// Accesses a capture by its name or number. @@ -74,15 +46,11 @@ extension Regex.Match { // Note: We should be able to get the element offset from the key path // itself even at compile time. We need a better way of doing this. guard let outputTupleOffset = MemoryLayout.tupleElementIndex( - of: keyPath, elementTypes: [wholeMatchType] + anyRegexOutput.map(\.type) + of: keyPath, elementTypes: anyRegexOutput.map(\.type) ) else { return output[keyPath: keyPath] } - if outputTupleOffset == 0 { - return value.map { $0 as! T } ?? (input[range] as! T) - } else { - return anyRegexOutput[outputTupleOffset - 1].value as! T - } + return anyRegexOutput[outputTupleOffset].value as! T } /// Accesses a capture using the `.0` syntax, even when the match isn't a tuple. @@ -100,9 +68,8 @@ extension Regex.Match { ) else { preconditionFailure("Reference did not capture any match in the regex") } - return element.existentialOutputComponent( - from: input[...] + from: input ) as! Capture } } diff --git a/Sources/_StringProcessing/Utility/TypeVerification.swift b/Sources/_StringProcessing/Utility/TypeVerification.swift index 0ad8aa325..c3aa53c7a 100644 --- a/Sources/_StringProcessing/Utility/TypeVerification.swift +++ b/Sources/_StringProcessing/Utility/TypeVerification.swift @@ -18,10 +18,10 @@ extension Regex { return true } - var tupleElements: [Any.Type] = [Substring.self] - var labels = " " + var tupleElements: [Any.Type] = [] + var labels = "" - for capture in program.tree.root._captureList.captures { + for capture in program.tree.captureList.captures { var captureType: Any.Type = capture.type ?? Substring.self var i = capture.optionalDepth @@ -41,7 +41,7 @@ extension Regex { // If we have no captures, then our Regex must be Regex. if tupleElements.count == 1 { - return Output.self == Substring.self + return Output.self == program.tree.root.wholeMatchType } let createdType = TypeConstruction.tupleType( diff --git a/Sources/_StringProcessing/Utility/TypedIndex.swift b/Sources/_StringProcessing/Utility/TypedIndex.swift index adde06a3e..c95e7f93b 100644 --- a/Sources/_StringProcessing/Utility/TypedIndex.swift +++ b/Sources/_StringProcessing/Utility/TypedIndex.swift @@ -78,11 +78,11 @@ extension TypedIndex: BidirectionalCollection where C: BidirectionalCollection { // failure in the Swift repo. #if false extension TypedIndex: RangeReplaceableCollection where C: RangeReplaceableCollection { - init() { rawValue = C() } + init() { content = C() } mutating func replaceSubrange(_ subrange: Range, with newElements: C) where C : Collection, C.Element == Element { - let rawRange = subrange.lowerBound.rawValue ..< subrange.upperBound.rawValue - rawValue.replaceSubrange(rawRange, with: newElements) + let rawRange = subrange.lowerBound.content ..< subrange.upperBound.content + content.replaceSubrange(rawRange, with: newElements) } // TODO: append, and all the other customization hooks... diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 5a88adf6b..a2ed03dae 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -598,10 +598,10 @@ class RegexDSLTests: XCTestCase { let regex3 = Regex { OneOrMore("a") Capture { - TryCapture("b") { Int($0) } - ZeroOrMore { - TryCapture("c") { Double($0) } - } + TryCapture("b", transform: { Int($0) }) + ZeroOrMore( + TryCapture("c", transform: { Double($0) }) + ) Optionally("e") } } @@ -909,57 +909,64 @@ class RegexDSLTests: XCTestCase { } } } - - func testSemanticVersionExample() { - struct SemanticVersion: Equatable { - var major: Int - var minor: Int - var patch: Int - var dev: String? - } - struct SemanticVersionParser: CustomConsumingRegexComponent { - typealias RegexOutput = SemanticVersion - func consuming( - _ input: String, - startingAt index: String.Index, - in bounds: Range - ) throws -> (upperBound: String.Index, output: SemanticVersion)? { - let regex = Regex { - TryCapture(OneOrMore(.digit)) { Int($0) } + + struct SemanticVersion: Equatable { + var major: Int + var minor: Int + var patch: Int + var dev: String? + } + struct SemanticVersionParser: CustomConsumingRegexComponent { + typealias RegexOutput = SemanticVersion + func consuming( + _ input: String, + startingAt index: String.Index, + in bounds: Range + ) throws -> (upperBound: String.Index, output: SemanticVersion)? { + let regex = Regex { + TryCapture(OneOrMore(.digit)) { Int($0) } + "." + TryCapture(OneOrMore(.digit)) { Int($0) } + Optionally { "." TryCapture(OneOrMore(.digit)) { Int($0) } - Optionally { - "." - TryCapture(OneOrMore(.digit)) { Int($0) } - } - Optionally { - "-" - Capture(OneOrMore(.word)) - } } + Optionally { + "-" + Capture(OneOrMore(.word)) + } + } - guard let match = input[index..