diff --git a/Documentation/Evolution/RegexBuilderDSL.md b/Documentation/Evolution/RegexBuilderDSL.md new file mode 100644 index 000000000..f0a477644 --- /dev/null +++ b/Documentation/Evolution/RegexBuilderDSL.md @@ -0,0 +1,1446 @@ +# Regex builder DSL + +* Proposal: [SE-NNNN](NNNN-filename.md) +* Authors: [Richard Wei](https://github.com/rxwei) +* Review Manager: TBD +* Implementation: [apple/swift-experimental-string-processing](https://github.com/apple/swift-experimental-string-processing/tree/main/Sources/_StringProcessing/RegexDSL) +* Status: **Pitch** + +**Table of Contents** +- [Introduction](#introduction) +- [Motivation](#motivation) +- [Proposed solution](#proposed-solution) +- [Detailed design](#detailed-design) + - [`RegexComponent` protocol](#regexcomponent-protocol) + - [Concatenation](#concatenation) + - [Alternation](#alternation) + - [Quantification](#quantification) + - [Capture and reference](#capture-and-reference) + - [Subpattern](#subpattern) +- [Source compatibility](#source-compatibility) +- [Effect on ABI stability](#effect-on-abi-stability) +- [Effect on API resilience](#effect-on-api-resilience) +- [Alternatives considered](#alternatives-considered) + +## Introduction + +[Declarative string processing] aims to offer powerful pattern matching capabilities with expressivity, clarity, type safety, and ease of use. To achieve this, we propose to introduce a result-builder-based DSL, **regex builder**, for creating and composing regular expressions (**regex**es). + +Regex builder is part of the Swift Standard Library but resides in a standalone module named `RegexBuilder`. By importing `RegexBuilder`, you get all necessary API for building a regex. + +```swift +import RegexBuilder + +let emailPattern = Regex { + let word = OneOrMore(.word) + Capture { + ZeroOrMore { + word + "." + } + word + } + "@" + Capture { + word + OneOrMore { + "." + word + } + } +} // => Regex<(Substring, Substring, Substring)> + +let email = "My email is my.name@mail.swift.org." +if let match = email.firstMatch(of: emailPattern) { + let (wholeMatch, name, domain) = match.output + // wholeMatch: "My email is my.name@mail.swift.org." + // name: "my.name" + // domain: "mail.swift.org" +} +``` + +This proposal introduces all core API for creating and composing regexes that echos the textual [regex syntax] and [strongly typed regex captures], but does not formally specify the matching semantics or define character classes. + +## Motivation + +Regex is a fundemental and powerful tool for textual pattern matching. It is a domain-specific language often expressed as text. For example, given the following bank statement: + +``` +CREDIT 04062020 PayPal transfer $4.99 +CREDIT 04032020 Payroll $69.73 +DEBIT 04022020 ACH transfer $38.25 +DEBIT 03242020 IRS tax payment $52249.98 +``` + +One can write the follow textual regex to match each line: + +``` +(CREDIT|DEBIT)\s+(\d{2}\d{2}\d{4})\s+([\w\s]+\w)\s+(\$\d+\.\d{2}) +``` + +While a regex like this is very compact and expressive, it is very difficult read, write and use: + +1. Syntactic special characters, e.g. `\`, `(`, `[`, `{`, are too dense to be readable. +2. It contains a hierarchy of subpatterns fit into a single line of text. +3. No code completion when typing syntactic components. +4. Capturing groups produce raw data (i.e. a range or a substring) and can only be converted to other data structures after matching. +5. While comments `(?#...)` can be added inline, it only complicates readability. + +## Proposed solution + +We introduce regex builder, a result-builder-based API for creating and composing regexes. This API resides in a new module named `RegexBuilder` that is to be shipped as part of the Swift toolchain. + +With regex builder, the regex for matching a bank statement can be written as the following: + +```swift +import RegexBuilder + +enum TransactionKind: String { + case credit = "CREDIT" + case debit = "DEBIT" +} + +struct Date { + var month, day, year: Int + init?(mmddyyyy: String) { ... } +} + +struct Amount { + var valueTimes100: Int + init?(twoDecimalPlaces text: Substring) { ... } +} + +let statementPattern = Regex { + // Parse the transaction kind. + TryCapture { + ChoiceOf { + "CREDIT" + "DEBIT" + } + } transform: { + TransactionKind(rawValue: String($0)) + } + OneOrMore(.whitespace) + // Parse the date, e.g. "01012021". + TryCapture { + Repeat(.digit, count: 2) + Repeat(.digit, count: 2) + Repeat(.digit, count: 4) + } transform: { Date(mmddyyyy: $0) } + OneOrMore(.whitespace) + // Parse the transaction description, e.g. "ACH transfer". + Capture { + OneOrMore(.custom([ + .characterClass(.word), + .characterClass(.whitespace) + ])) + CharacterClass.word + } transform: { String($0) } + OneOrMore(.whitespace) + "$" + // Parse the amount, e.g. `$100.00`. + TryCapture { + OneOrMore(.digit) + "." + Repeat(.digit, count: 2) + } transform: { Amount(twoDecimalPlaces: $0) } +} // => Regex<(Substring, TransactionKind, Date, String, Amount)> + + +let statement = """ + CREDIT 04062020 PayPal transfer $4.99 + CREDIT 04032020 Payroll $69.73 + DEBIT 04022020 ACH transfer $38.25 + DEBIT 03242020 IRS tax payment $52249.98 + """ +for match in statement.matches(of: statementPattern) { + let (line, kind, date, description, amount) = match.output + ... +} +``` + +Regex builder addresses all of textual regexes' shortcomings presented in the [Motivation](#motivation) section: +1. Capture groups and quantifiers are expressed as API calls that are easy to read. +2. Scoping and indentations clearly distinguish subpatterns in the hierarchy. +3. Code completion is available when the developer types an API call. +4. Capturing groups can be transformed into structured data at the regex declaration site. +5. Normal code comments can be written within a regex declaration to further improve readability. + +## Detailed design + +### `RegexComponent` protocol + +One of the goals of the regex builder DSL is allowing the developers to easily compose regexes from common currency types and literals, or even define custom patterns to use for matching. We introduce `RegexComponent`, a protocol that unifies all types that can represent a component of a regex. + +```swift +public protocol RegexComponent { + associatedtype Output + @RegexComponentBuilder + var regex: Regex { get } +} +``` + +By conforming standard library types to `RegexComponent`, we allow them to be used inside the regex builder DSL as a match target. + +```swift +// A string represents a regex that matches the string. +extension String: RegexComponent { + public var regex: Regex { get } +} + +// A substring represents a regex that matches the substring. +extension Substring: RegexComponent { + public var regex: Regex { get } +} + +// A character represents a regex that matches the character. +extension Character: RegexComponent { + public var regex: Regex { get } +} + +// A unicode scalar represents a regex that matches the scalar. +extension UnicodeScalar: RegexComponent { + public var regex: Regex { get } +} + +// To be introduced in a future pitch. +extension CharacterClass: RegexComponent { + public var regex: Regex { get } +} +``` + +Since regexes are composable, the `Regex` type itself also conforms to `RegexComponent`. + +```swift +extension Regex: RegexComponent { + public var regex: Self { self } +} +``` + +All of the regex builder DSL in the rest of this pitch will accept generic components that conform to `RegexComponent`. + +### Concatenation + +A regex can be viewed as a concatenation of smaller regexes. In the regex builder DSL, `RegexComponentBuilder` is the basic facility to allow developers to compose regexes by concatenation. + +```swift +@resultBuilder +public enum RegexComponentBuilder { ... } +``` + +A closure marked with `@RegexComponentBuilder` will be transformed to produce a `Regex` by concatenating all of its components, where the result type's `Output` type will be a `Substring` followed by concatenated captures (tuple when plural). + +> #### Recap: Regex capturing basics +> +> `Regex` is a generic type with generic parameter `Output`. +> +> ```swift +> struct Regex { ... } +> ``` +> +> When a regex does not contain any capturing groups, its `Output` type is `Substring`, which represents the whole matched portion of the input. +> +> ```swift +> let noCaptures = #/a/# // => Regex +> ``` +> +> When a regex contains capturing groups, i.e. `(...)`, the `Output` type is extended as a tuple to also contain *capture types*. Capture types are tuple elements after the first element. +> +> ```swift +> // ________________________________ +> // .0 | .0 | +> // ____________________ _________ +> let yesCaptures = #/a(?:(b+)c(d+))+e(f)?/# // => Regex<(Substring, Substring, Substring, Substring?)> +> // ---- ---- --- --------- --------- ---------- +> // .1 | .2 | .3 | .1 | .2 | .3 | +> // | | | | | | +> // | | |_______________________________ | ______ | ________| +> // | | | | +> // | |______________________________________ | ______ | +> // | | +> // |_____________________________________________| +> // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +> // Capture types +> ``` + +We introduce a new initializer `Regex.init(_:)` which accepts a `@RegexComponentBuilder` closure. This initializer is the entry point for creating a regex using the regex builder DSL. + +```swift +extension Regex { + public init( + @RegexComponentBuilder _ content: () -> R + ) where R.Output == Output +} +``` + +Example: + +```swift +Regex { + regex0 // Regex + regex1 // Regex<(Substring, Int)> + if condition { + regex2 // Regex<(Substring, Float)> + } else { + regex3 // Regex<(Substring, Substring)> + } +} // Regex<(Substring, Int, Float, Substring)> +``` + +This above regex will be transformed to: + +```swift +Regex { + let e0 = RegexComponentBuilder.buildExpression(regex0) // Regex + let e1 = RegexComponentBuilder.buildExpression(regex1) // Regex<(Substring, Int)> + let e2: Regex + if condition { + e2 = RegexComponentBuilder.buildEither(first: regex2) // Regex<(Substring, Float)> + } else { + e2 = RegexComponentBuilder.buildEither(second: regex3) // Regex<(Substring, Substring)> + } + let r0 = RegexComponentBuilder.buildPartialBlock(first: e0) + let r1 = RegexComponentBuilder.buildPartialBlock(accumulated: r0, next: r1) + let r2 = RegexComponentBuilder.buildPartialBlock(accumulated: r1, next: r2) + return r2 +} // Regex<(Substring, Int, Float, Substring)> +``` + +Basic methods in `RegexComponentBuilder`, e.g. `buildBlock()`, provides support for creating the most fundamental blocks. The `buildExpression` method wraps a user-provided component in a `RegexComponentBuilder.Component` structure, before passing the component to other builder methods. This is used for saving the source location of the component so that runtime errors can be reported with an accurate location. + +```swift +@resultBuilder +public enum RegexComponentBuilder { + /// Returns an empty regex. + public static func buildBlock() -> Regex + + /// A builder component that stores a regex component and its source location + /// for debugging purposes. + public struct Component { + public var value: Value + public var file: String + public var function: String + public var line: Int + public var column: Int + } + + /// Returns a component by wrapping the component regex in `Component` and + /// recording its source location. + public static func buildExpression( + _ regex: R, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column + ) -> Component +} +``` + +When it comes to concatenation, `RegexComponentBuilder` utilizes the [recently proposed `buildPartialBlock` feature](https://forums.swift.org/t/pitch-buildpartialblock-for-result-builders/55561/1) to be able to concatenate all components' capture types to a single result tuple. `buildPartialBlock(first:)` provides support for creating a regex from a single component, and `buildPartialBlock(accumulated:next:)` support for creating a regex from multiple results. + +Before Swift supports variadic generics, `buildPartialBlock(first:)` and `buildPartialBlock(accumulated:next:)` must be overloaded to support concatenating regexes of supported capture quantities (arities). +- `buildPartialBlock(first:)` is overloaded `arity` times such that a unary block with a component of any supported capture arity will produce a regex with capture type `Substring` followed by the component's capture types. The base overload, `buildPartialBlock(first:) -> Regex`, must be marked with `@_disfavoredOverload` to prevent it from shadowing other overloads. +- `buildPartialBlock(accumulated:next:)` is overloaded up to `arity^2` times to account for all possible pairs of regexes that make up 10 captures. + +In the initial version of the DSL, we plan to support regexes with up to 10 captures, as 10 captures are sufficient for most use cases. These overloads can be superceded by variadic versions of `buildPartialBlock(first:)` and `buildPartialBlock(accumulated:next:)` in a future release. + +```swift +extension RegexComponentBuilder { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildPartialBlock< + // R, WholeMatch, Capture... + // >( + // first component: Component + // ) -> Regex<(Substring, Capture...)> + // where Component.Output == (WholeMatch, Capture...), + + @_disfavoredOverload + public static func buildPartialBlock( + first r: Component + ) -> Regex + + public static func buildPartialBlock( + first r: Component + ) -> Regex<(Substring, C0)> where R.Output == (W, C0) + + public static func buildPartialBlock( + first r: Component + ) -> Regex<(Substring, C0, C1)> where R.Output == (W, C0, C1) + + // ... `O(arity)` overloads of `buildPartialBlock(first:)` + + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildPartialBlock< + // AccumulatedWholeMatch, NextWholeMatch, + // AccumulatedCapture..., NextCapture..., + // Accumulated: RegexComponent, Next: RegexComponent + // >( + // accumulated: Accumulated, next: Component + // ) -> Regex<(Substring, AccumulatedCapture..., NextCapture...)> + // where Accumulated.Output == (AccumulatedWholeMatch, AccumulatedCapture...), + // Next.Output == (NextWholeMatch, NextCapture...) + + public static func buildPartialBlock( + accumulated: R0, next: Component + ) -> Regex<(Substring, C0)> where R0.Output == W0, R1.Output == (W1, C0) + + public static func buildPartialBlock( + accumulated: R0, next: Component + ) -> Regex<(Substring, C0, C1)> where R0.Output == W0, R1.Output == (W1, C0, C1) + + public static func buildPartialBlock( + accumulated: R0, next: Component + ) -> Regex<(Substring, C0, C1, C2)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2) + + // ... `O(arity^2)` overloads of `buildPartialBlock(accumulated:next:)` +} +``` + +To support `if` statements, `buildEither(first:)`, `buildEither(second:)` and `buildOptional(_:)` are defined with overloads to support up to 10 captures because each capture type needs to be transformed to an optional. The overload for non-capturing regexes, due to the lack of generic constraints, must be annotated with `@_disfavoredOverload` in order not shadow other overloads. We expect that a variadic-generic version of this method will eventually superseded all of these overloads. + +```swift +extension RegexComponentBuilder { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildEither< + // Component, WholeMatch, Capture... + // >( + // first component: Component + // ) -> Regex<(Substring, Capture...)> + // where Component.Output == (WholeMatch, Capture...) + + public static func buildEither( + first component: Component + ) -> Regex { + component + } + + public static func buildEither( + first component: Component + ) -> Regex<(Substring, C0)> where R.Output == (W, C0) { + component + } + + public static func buildEither( + first component: Component + ) -> Regex<(Substring, C0, C1)> where R.Output == (W, C0, C1) { + component + } + + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildEither< + // Component, WholeMatch, Capture... + // >( + // second component: Component + // ) -> Regex<(Substring, Capture...)> + // where Component.Output == (WholeMatch, Capture...) + + public static func buildEither( + second component: Component + ) -> Regex { + component + } + + public static func buildEither( + second component: Component + ) -> Regex<(Substring, C0)> where R.Output == (W, C0) { + component + } + + public static func buildEither( + second component: Component + ) -> Regex<(Substring, C0, C1)> where R.Output == (W, C0, C1) { + component + } + + // ... `O(arity)` overloads of `buildEither(_:)` + + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildOptional< + // Component, WholeMatch, Capture... + // >( + // _ component: Component? + // ) where Component.Output == (WholeMatch, Capture...) + + @_disfavoredOverload + public static func buildOptional( + _ component: Component? + ) -> Regex + + public static func buildOptional( + _ component: Component? + ) -> Regex<(Substring, C0?)> + + public static func buildOptional( + _ component: Component? + ) -> Regex<(Substring, C0?, C1?)> + + // ... `O(arity)` overloads of `buildOptional(_:)` +} +``` + +To support `if #available(...)` statements, `buildLimitedAvailability(_:)` is defined with overloads to support up to 10 captures. Similar to `buildOptional`, the overload for non-capturing regexes must be annotated with `@_disfavoredOverload`. + +```swift +extension RegexComponentBuilder { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildLimitedAvailability< + // Component, WholeMatch, Capture... + // >( + // _ component: Component + // ) where Component.Output == (WholeMatch, Capture...) + + @_disfavoredOverload + public static func buildLimitedAvailability( + _ component: Component + ) -> Regex + + public static func buildLimitedAvailability( + _ component: Component + ) -> Regex<(Substring, C0?)> + + public static func buildLimitedAvailability( + _ component: Component + ) -> Regex<(Substring, C0?, C1?)> + + // ... `O(arity)` overloads of `buildLimitedAvailability(_:)` +} +``` + +### Alternation + +Alternations are used to match one of multiple patterns. An alternation wraps its underlying patterns' capture types in an `Optional` and concatenates them together, first to last. + +```swift +let choice = ChoiceOf { + regex1 // Regex<(Substring, Int)> + regex2 // Regex<(Substring, Float)> + regex3 // Regex<(Substring, Substring)> + regex0 // Regex +} // => Regex<(Substring, Int?, Float?, Substring?)> +``` + +`AlternationBuilder` is a result builder type for creating alternations from components of a block. + +```swift +@resultBuilder +public struct AlternationBuilder { ... } +``` + +To the developer, the top-level API is a type named `ChoiceOf`. This type has an initializer that accepts an `@AlternationBuilder` closure. + +```swift +public struct ChoiceOf: RegexComponent { + public var regex: Regex { get } + public init( + @AlternationBuilder builder: () -> R + ) where R.Output == Output +} +``` + +`AlternationBuilder` is mostly similar to `RegexComponent` with the following distinctions: +- Empty blocks are not supported. +- Capture types are wrapped in a layer of `Optional` before being concatenated in the resulting `Output` type. +- `buildEither(first:)` and `buildEither(second:)` are overloaded for each supported capture arity because they need to wrap capture types in `Optional`. + +```swift +@resultBuilder +public enum AlternationBuilder { + public typealias Component = RegexComponentBuilder.Component + + /// Returns a component by wrapping the component regex in `Component` and + /// recording its source location. + public static func buildExpression( + _ regex: R, + file: String = #file, + function: String = #function, + line: Int = #line, + column: Int = #column + ) -> Component + + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildPartialBlock< + // R, WholeMatch, Capture... + // >( + // first component: Component + // ) -> Regex<(Substring, Capture?...)> + // where Component.Output == (WholeMatch, Capture...), + + @_disfavoredOverload + public static func buildPartialBlock( + first r: Component + ) -> Regex + + public static func buildPartialBlock( + first r: Component + ) -> Regex<(Substring, C0?)> where R.Output == (W, C0) + + public static func buildPartialBlock( + first r: Component + ) -> Regex<(Substring, C0?, C1?)> where R.Output == (W, C0, C1) + + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildPartialBlock< + // AccumulatedWholeMatch, NextWholeMatch, + // AccumulatedCapture..., NextCapture..., + // Accumulated: RegexComponent, Next: RegexComponent + // >( + // accumulated: Accumulated, next: Component + // ) -> Regex<(Substring, AccumulatedCapture..., NextCapture...)> + // where Accumulated.Output == (AccumulatedWholeMatch, AccumulatedCapture...), + // Next.Output == (NextWholeMatch, NextCapture...) + + public static func buildPartialBlock( + accumulated: R0, next: Component + ) -> Regex<(Substring, C0?)> where R0.Output == W0, R1.Output == (W1, C0) + + public static func buildPartialBlock( + accumulated: R0, next: Component + ) -> Regex<(Substring, C0?, C1?)> where R0.Output == W0, R1.Output == (W1, C0, C1) + + public static func buildPartialBlock( + accumulated: R0, next: Component + ) -> Regex<(Substring, C0?, C1?, C2?)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2) + + // ... `O(arity^2)` overloads of `buildPartialBlock(accumulated:next:)` +} + +extension AlternationBuilder { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildEither< + // R, WholeMatch, Capture... + // >( + // first component: Component + // ) -> Regex<(Substring, Component?...)> + // where R.Output == (WholeMatch, Capture...) + + @_disfavoredOverload + public static func buildEither( + first component: Component + ) -> Regex + + public static func buildEither( + first component: Component + ) -> Regex<(Substring, C0?)> + + public static func buildEither( + first component: Component + ) -> Regex<(Substring, C0?, C1?)> + + // ... `O(arity)` overloads of `buildEither(_:)` + + public static func buildEither( + first component: Component + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8, C9?)> where R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) +} + +extension AlternationBuilder { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildEither< + // R, WholeMatch, Capture... + // >( + // second component: Component + // ) -> Regex<(Substring, Capture?...)> + // where R.Output == (WholeMatch, Capture...) + + @_disfavoredOverload + public static func buildEither( + second component: Component + ) -> Regex + + public static func buildEither( + second component: Component + ) -> Regex<(Substring, C0?)> + + public static func buildEither( + second component: Component + ) -> Regex<(Substring, C0?, C1?)> + + // ... `O(arity)` overloads of `buildEither(_:)` + + public static func buildEither( + second component: Component + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8, C9?)> where R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) +} + +extension AlternationBuilder { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildOptional< + // Component, WholeMatch, Capture... + // >( + // _ component: Component? + // ) -> Regex<(Substring, Capture?...)> + // where Component.Output == (WholeMatch, Capture...) + + @_disfavoredOverload + public static func buildOptional( + _ component: Component? + ) -> Regex + + public static func buildOptional( + _ component: Component? + ) -> Regex<(Substring, C0?)> + + public static func buildOptional( + _ component: Component? + ) -> Regex<(Substring, C0?, C1?)> + + // ... `O(arity)` overloads of `buildOptional(_:)` + + public static func buildOptional( + _ component: Component? + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8, C9?)> where R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) +} + +extension AlternationBuilder { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single method: + // + // public static func buildLimitedAvailability< + // Component, WholeMatch, Capture... + // >( + // _ component: Component + // ) -> Regex<(Substring, Capture?...)> + // where Component.Output == (WholeMatch, Capture...) + + @_disfavoredOverload + public static func buildLimitedAvailability( + _ component: Component + ) -> Regex + + public static func buildLimitedAvailability( + _ component: Component + ) -> Regex<(Substring, C0?)> + + public static func buildLimitedAvailability( + _ component: Component + ) -> Regex<(Substring, C0?, C1?)> + + // ... `O(arity)` overloads of `buildLimitedAvailability(_:)` + + public static func buildLimitedAvailability( + _ component: Component + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8, C9?)> where R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) +} +``` + +### Quantification + +Quantifiers are free functions that take a regex or a `@RegexComponentBuilder` closure that produces a regex. The result is a regex whose `Output` type is the same as the argument's, when the lower bound of quantification is greater than `0`; otherwise, it is an `Optional` thereof. + +Quantifiers are generic types that can be created from a regex component. Their `Output` type is inferred from initializers. Each of these types corresponds to a quantifier in the textual regex. + +| Quantifier in regex builder | Quantifier in textual regex | +|-----------------------------|-----------------------------| +| `OneOrMore(...)` | `...+` | +| `ZeroOrMore(...)` | `...*` | +| `Optionally(...)` | `...?` | +| `Repeat(..., count: n)` | `...{n}` | +| `Repeat(..., n...)` | `...{n,}` | +| `Repeat(..., n...m)` | `...{n,m}` | + +```swift +public struct OneOrMore: RegexComponent { + public var regex: Regex { get } +} + +public struct ZeroOrMore: RegexComponent { + public var regex: Regex { get } +} + +public struct Optionally: RegexComponent { + public var regex: Regex { get } +} + +public struct Repeat: RegexComponent { + public var regex: Regex { get } +} +``` + +Like quantifiers in textual regexes, the developer can specify how eager the pattern should be matched against using `QuantificationBehavior`. Static properties in `QuantificationBehavior` are named like adverbs for fluency at a quantifier call site. + +```swift +/// Specifies how much to attempt to match when using a quantifier. +public struct QuantificationBehavior { + /// Match as much of the input string as possible, backtracking when + /// necessary. + public static var eagerly: QuantificationBehavior { get } + + /// Match as little of the input string as possible, expanding the matched + /// region as necessary to complete a match. + public static var reluctantly: QuantificationBehavior { get } + + /// Match as much of the input string as possible, performing no backtracking. + public static var possessively: QuantificationBehavior { get } +} +``` + +Each quantification behavior corresponds to a quantification behavior in the textual regex. + +| Quantifier behavior in regex builder | Quantifier behavior in textual regex | +|--------------------------------------|--------------------------------------| +| `.eagerly` | no suffix | +| `.reluctantly` | suffix `?` | +| `.possessively` | suffix `+` | + +`OneOrMore` and count-based `Repeat` are quantifiers that produce a new regex with the original capture types. Their `Output` type is `Substring` followed by the component's capture types. `ZeroOrMore`, `Optionally`, and range-based `Repeat` are quantifiers that produce a new regex with optional capture types. Their `Output` type is `Substring` followed by the component's capture types wrapped in `Optional`. + +| Quantifier | Component `Output` | Result `Output` | +|------------------------------------------------------|----------------------------|----------------------------| +| `OneOrMore`
`Repeat(..., count: ...)` | `(WholeMatch, Capture...)` | `(Substring, Capture...)` | +| `OneOrMore`
`Repeat(..., count: ...)` | `WholeMatch` (non-tuple) | `Substring` | +| `ZeroOrMore`
`Optionally`
`Repeat(..., n...m)` | `(WholeMatch, Capture...)` | `(Substring, Capture?...)` | +| `ZeroOrMore`
`Optionally`
`Repeat(..., n...m)` | `WholeMatch` (non-tuple) | `Substring` | + +Due to the lack of variadic generics, these functions must be overloaded for every supported capture arity. + +```swift +extension OneOrMore { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single set of methods: + // + // public init< + // Component: RegexComponent, WholeMatch, Capture... + // >( + // _ component: Component, + // _ behavior: QuantificationBehavior = .eagerly + // ) + // where Output == (Substring, Capture...)>, + // Component.Output == (WholeMatch, Capture...) + // + // public init< + // Component: RegexComponent, WholeMatch, Capture... + // >( + // _ behavior: QuantificationBehavior = .eagerly, + // @RegexComponentBuilder _ component: () -> Component + // ) + // where Output == (Substring, Capture...), + // Component.Output == (WholeMatch, Capture...) + + @_disfavoredOverload + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == Substring + + @_disfavoredOverload + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring + + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0), Component.Output == (W, C0) + + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0), Component.Output == (W, C0) + + // ... `O(arity)` overloads +} + +extension ZeroOrMore { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single set of methods: + // + // public init< + // Component: RegexComponent, WholeMatch, Capture... + // >( + // _ component: Component, + // _ behavior: QuantificationBehavior = .eagerly + // ) + // where Output == (Substring, Capture?...)>, + // Component.Output == (WholeMatch, Capture...) + // + // public init< + // Component: RegexComponent, WholeMatch, Capture... + // >( + // _ behavior: QuantificationBehavior = .eagerly, + // @RegexComponentBuilder _ component: () -> Component + // ) + // where Output == (Substring, Capture?...), + // Component.Output == (WholeMatch, Capture...) + + @_disfavoredOverload + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == Substring + + @_disfavoredOverload + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring + + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?), Component.Output == (W, C0) + + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?), Component.Output == (W, C0) + + // ... `O(arity)` overloads +} + +extension Optionally { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single set of methods: + // + // public init< + // Component: RegexComponent, WholeMatch, Capture... + // >( + // _ component: Component, + // _ behavior: QuantificationBehavior = .eagerly + // ) + // where Output == (Substring, Capture?...), + // Component.Output == (WholeMatch, Capture...) + // + // public init< + // Component: RegexComponent, WholeMatch, Capture... + // >( + // _ behavior: QuantificationBehavior = .eagerly, + // @RegexComponentBuilder _ component: () -> Component + // ) + // where Output == (Substring, Capture?...)>, + // Component.Output == (WholeMatch, Capture...) + + @_disfavoredOverload + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == Substring + + @_disfavoredOverload + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring + + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?), Component.Output == (W, C0) + + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?), Component.Output == (W, C0) + + // ... `O(arity)` overloads +} + +extension Repeat { + // The following builder methods implement what would be possible with + // variadic generics (using imaginary syntax) as a single set of methods: + // + // public init< + // Component: RegexComponent, WholeMatch, Capture... + // >( + // _ component: Component, + // count: Int, + // _ behavior: QuantificationBehavior = .eagerly + // ) + // where Output == (Substring, Capture...), + // Component.Output == (WholeMatch, Capture...) + // + // public init< + // Component: RegexComponent, WholeMatch, Capture... + // >( + // count: Int, + // _ behavior: QuantificationBehavior = .eagerly, + // @RegexComponentBuilder _ component: () -> Component + // ) + // where Output == (Substring, Capture...), + // Component.Output == (WholeMatch, Capture...) + // + // public init< + // Component: RegexComponent, WholeMatch, Capture..., RE: RangeExpression + // >( + // _ component: Component, + // _ expression: RE, + // _ behavior: QuantificationBehavior = .eagerly + // ) + // where Output == (Substring, Capture?...), + // Component.Output == (WholeMatch, Capture...) + // + // public init< + // Component: RegexComponent, WholeMatch, Capture..., RE: RangeExpression + // >( + // _ expression: RE, + // _ behavior: QuantificationBehavior = .eagerly, + // @RegexComponentBuilder _ component: () -> Component + // ) + // where Output == (Substring, Capture?...), + // Component.Output == (WholeMatch, Capture...) + + // Nullary + + @_disfavoredOverload + public init( + _ component: Component, + count: Int, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == Substring, R.Bound == Int + + @_disfavoredOverload + public init( + count: Int, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring, R.Bound == Int + + @_disfavoredOverload + public init( + _ component: Component, + _ expression: RE, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == Substring, R.Bound == Int + + @_disfavoredOverload + public init( + _ expression: RE, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring, R.Bound == Int + + + // Unary + + public init( + _ component: Component, + count: Int, + _ behavior: QuantificationBehavior = .eagerly + ) + where Output == (Substring, C0), + Component.Output == (Substring, C0), + R.Bound == Int + + public init( + count: Int, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) + where Output == (Substring, C0), + Component.Output == (Substring, C0), + R.Bound == Int + + public init( + _ component: Component, + _ expression: RE, + _ behavior: QuantificationBehavior = .eagerly + ) + where Output == (Substring, C0?), + Component.Output == (W, C0), + R.Bound == Int + + public init( + _ expression: RE, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) + where Output == (Substring, C0?), + Component.Output == (W, C0), + R.Bound == Int + + // ... `O(arity)` overloads +} +``` + +### Capture and reference + +`Capture` and `TryCapture` produce a new `Regex` by inserting the captured pattern's whole match (`.0`) to the `.1` position of `Output`. When a transform closure is provided, the whole match of the captured content will be transformed to using the closure. + +```swift +public struct Capture: RegexComponent { + public var regex: Regex { get } +} + +public struct TryCapture: RegexComponent { + public var regex: Regex { get } +} +``` + +The difference between `Capture` and `TryCapture` is that `TryCapture` works better with transform closures that can return `nil` or throw, whereas `Capture` relies on the user to handle errors within a transform closure. With `TryCapture`, when the closure returns `nil` or throws, the failure becomes a no-match. + +```swift +// Below are `Capture` and `TryCapture` initializer variants on capture arity 0. +// Higher capture arities are omitted for simplicity. + +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W), R.Output == W + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W), R.Output == W + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W + + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W), R.Output == W + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W), R.Output == W +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture), R.Output == W + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture), R.Output == W + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture), R.Output == W + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture), R.Output == W + + // ... `O(arity)` overloads +} +``` + +Example: + +```swift +let regex = Regex { + OneOrMore("a") + Capture { + TryCapture("b") { Int($0) } + ZeroOrMore { + TryCapture("c") { Double($0) } + } + Optionally("e") + } +} +``` + +Variants of `Capture` and `TryCapture` accept a `Reference` argument. References can be used to achieve named captures and named backreferences from textual regexes. + +```swift +public struct Reference: RegexComponent { + public init(_ captureType: Capture.Type = Capture.self) + public var regex: Regex +} + +extension Regex.Match { + public subscript(_ reference: Reference) -> Capture { get } +} +``` + +When capturing some regex with a reference specified, the reference will refer to the most recently captured content. The reference itself can be used as a regex to match the most recently captured content, or as a name to look up the result of matching. + +```swift +let a = Reference(Substring.self) +let b = Reference(Substring.self) +let regex = Regex { + Capture("abc", as: a) + Capture("def", as: b) + a + Capture(b) +} + +if let result = input.firstMatch(of: regex) { + print(result[a]) // => "abc" + print(result[b]) // => "def" +} +``` + +A regex is considered invalid when it contains a use of reference without it ever being captured in the regex. When this occurs in the regex builder DSL, an runtime error will be reported. + +### Subpattern + +In textual regex, one can refer to a subpattern to avoid duplicating the subpattern, for example: + +``` +(you|I) say (goodbye|hello); (?1) say (?2) +``` + +The above regex is equivalent to + +``` +(you|I) say (goodbye|hello); (you|I) say (goodbye|hello) +``` + +With regex builder, there is no special API required to reuse existing subpatterns, as a subpattern can be defined modularly using a `let` binding inside or outside a regex builder closure. + +```swift +Regex { + let subject = ChoiceOf { + "I" + "you" + } + let object = ChoiceOf { + "goodbye" + "hello" + } + subject + "say" + object + ";" + subject + "say" + object +} +``` + +Sometimes, a textual regex may also use `(?R)` or `(?0)` to recusively evaluate the entire regex. For example, the following textual regex matches "I say you say I say you say hello". + +``` +(you|I) say (goodbye|hello|(?R)) +``` + +For this, `Regex` offers a special initializer that allows its pattern to recursively reference itself. This is somewhat akin to a fixed-point combinator. + +```swift +extension Regex { + public init( + @RegexComponentBuilder _ content: (Regex) -> R + ) where R.Output == Match +} +``` + +With this initializer, the above regex can be expressed as the following using regex builder. + +```swift +Regex { wholeSentence in + ChoiceOf { + "I" + "you" + } + "say" + ChoiceOf { + "goodbye" + "hello" + wholeSentence + } +} +``` + +## Source compatibility + +Regex builder will be shipped in a new module named `RegexBuilder`, and thus will not affect the source compatibility of the existing code. + +## Effect on ABI stability + +The proposed feature does not change the ABI of existing features. + +## Effect on API resilience + +The proposed feature relies heavily upon overloads of `buildBlock` and `buildPartialBlock(accumulated:next:)` to work for different capture arities. In the fullness of time, we are hoping for variadic generics to supercede existing overloads. Such a change should not involve ABI-breaking modifications as it is merely a change of overload resolution. + +## Alternatives considered + +### Operators for quantification and alternation + +While `ChoiceOf` and quantifier functions provide a general way of creating alternations and quantifications, we recognize that some synctactic sugar can be useful for creating one-liners like in textual regexes, e.g. infix operator `|`, postfix operator `*`, etc. + +```swift +// The following functions implement what would be possible with variadic +// generics (using imaginary syntax) as a single function: +// +// public func | < +// R0: RegexComponent, R1: RegexComponent, +// WholeMatch0, WholeMatch1, +// Capture0..., Capture1... +// >( +// _ r0: RegexComponent, +// _ r1: RegexComponent +// ) -> Regex<(Substring, Capture0?..., Capture1?...)> +// where R0.Output == (WholeMatch0, Capture0...), +// R1.Output == (WholeMatch1, Capture1...) + +@_disfavoredOverload +public func | (lhs: R0, rhs: R1) -> Regex where R0: RegexComponent, R1: RegexComponent { + +public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0) + +public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?, C1?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1) + +// ... `O(arity^2)` overloads. +``` + +However, like `RegexComponentBuilder.buildPartialBlock(accumulated:next:)`, operators such as `|`, `+`, `*`, `.?` require a large number of overloads to work with regexes of every capture arity, compounded by the fact that operator type checking is prone to performance issues in Swift. Here is a list of + +| Opreator | Meaning | Required number of overloads | +|---------------|---------------------------|------------------------------| +| Infix `\|` | Choice of two | `O(arity^2)` | +| Postfix `*` | Zero or more eagerly | `O(arity)` | +| Postfix `*?` | Zero or more reluctantly | `O(arity)` | +| Postfix `*+` | Zero or more possessively | `O(arity)` | +| Postfix `+` | One or more eagerly | `O(arity)` | +| Postfix `+?` | One or more reluctantly | `O(arity)` | +| Postfix `++` | One or more possessively | `O(arity)` | +| Postfix `.?` | Optionally eagerly | `O(arity)` | +| Postfix `.??` | Optionally reluctantly | `O(arity)` | +| Postfix `.?+` | Optionally possessively | `O(arity)` | + + When variadic generics are supported in the future, we may be able to define one function per operator and reduce type checking burdens. + +### Postfix `capture` and `tryCapture` methods + +An earlier iteration of regex builder declared `capture` and `tryCapture` as methods on `RegexComponent`, meaning that you can append `.capture(...)` to any subpattern within a regex to capture it. For example: + +```swift +Regex { + OneOrMore { + r0.capture() + r1 + }.capture() +} // => Regex<(Substring, Substring, Substring)> +``` + +However, there are two shortcomings of this design: + +1. When a subpattern to be captured contains multiple components, the developer has to explicitly group them using a `Regex { ... }` block. + + ```swift + let emailPattern = Regex { + let word = OneOrMore(.word) + Regex { // <= Had to explicitly group multiple components + ZeroOrMore { + word + "." + } + word + }.capture() + "@" + Regex { + word + OneOrMore { + "." + word + } + }.capture() + } // => Regex<(Substring, Substring, Substring)> + ``` + +2. When there are nested captures, it is harder to number the captures visually because the order `capture()` appears is flipped in the postfix (method) notation. + + ```swift + let emailSuffixPattern = Regex { + "@" + Regex { + word + OneOrMore { + "." + word.capture() // top-level domain (.0) + } + }.capture() // full domain (.1) + } // => Regex<(Substring, Substring, Substring)> + // + // full domain ^~~~~~~~~ + // top-level domain ^~~~~~~~~ + ``` + + In comparison, prefix notation (`Capture` and `TryCapture` as a types) makes it easier to visually capture captures as you can number captures in the order they appear from top to bottom. This is consistent with textual regexes where capturing groups are numbered by the left parenthesis of the group from left to right. + + ```swift + let emailSuffixPattern = Regex { + Capture { // full domain (.0) + word + OneOrMore { + "." + Capture(word) // top-level domain (.1) + } + } + } // => Regex<(Substring, Substring, Substring)> + // + // full domain ^~~~~~~~~ + // top-level domain ^~~~~~~~~ + ``` + +### Unify quantifiers under `Repeat` + +Since `Repeat` is the most general version of quantifiers, one could argue for all quantifiers to be unified under the type `Repeat`, for example: + +```swift +Repeat(oneOrMore: r) +Repeat(zeroOrMore: r) +Repeat(optionally: r) +``` + +However, given that one-or-more (`+`), zero-or-more (`*`) and optional (`?`) are the most common quantifiers in textual regexes, we believe that these quantifiers deserve their own type and should be written as a single word instead of two. This can also reduce visual clutter when the quantification is used in multiple places of a regex. + +### Free functions instead of types + +One could argue that type such as `OneOrMore` could be defined as a top-level function that returns `Regex`. While it is entirely possible to do so, it would lose the name scoping benefits of a type and pollute the top-level namespace with `O(arity^2)` overloads of quantifiers, `capture`, `tryCapture`, etc. This could be detrimental to the usefulness of code completion. + +Another reason to use types instead of free functions is consistency with existing result-builder-based DSLs such as SwiftUI. + +[Declarative String Processing]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/DeclarativeStringProcessing.md +[Strongly Typed Regex Captures]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/StronglyTypedCaptures.md +[Regex Syntax]: https://github.com/apple/swift-experimental-string-processing/blob/main/Documentation/Evolution/RegexSyntax.md diff --git a/Documentation/Evolution/RegexTypeOverview.md b/Documentation/Evolution/RegexTypeOverview.md new file mode 100644 index 000000000..6fe3bc0bf --- /dev/null +++ b/Documentation/Evolution/RegexTypeOverview.md @@ -0,0 +1,524 @@ + +# Regex Type and Overview + +- Authors: [Michael Ilseman](https://github.com/milseman) and the Standard Library Team + +## Introduction + +Swift strings provide an obsessively Unicode-forward model of programming with strings. String processing with `Collection`'s algorithms is woefully inadequate for many day-to-day tasks compared to other popular programming and scripting languages. + +We propose addressing this basic shortcoming through an effort we are calling regex. What we propose is more powerful, extensible, and maintainable than what is traditionally thought of as regular expressions from other programming languages. This effort is presented as 6 interrelated proposals: + +1. `Regex` and `Regex.Match` types with support for typed captures, both static and dynamic. +2. A best-in-class treatment of traditional, familiar regular expression syntax for run-time construction of regex. +3. A literal for compile-time construction of a regex with statically-typed captures, enabling powerful source tools. +4. An expressive and composable result-builder DSL, with support for capturing strongly-typed values. +5. A modern treatment of Unicode semantics and string processing. +6. A treasure trove of string processing algorithms, along with library-extensible protocols enabling industrial-strength parsers to be used seamlessly as regex components. + +This proposal provides details on \#1, the `Regex` type and captures, and gives an overview of how each of the other proposals fit into regex in Swift. + +At the time of writing, these related proposals are in various states of being drafted, pitched, or proposed. For the current status, see [Pitch and Proposal Status][pitches]. + +
Obligatory differentiation from formal regular expressions + +Regular expressions originated in formal language theory as a way to answer yes-or-no whether a string is in a given [regular language](https://en.wikipedia.org/wiki/Regular_language). They are more powerful (and less composable) than [star-free languages](https://en.wikipedia.org/wiki/Star-free_language) and less powerful than [context-free languages](https://en.wikipedia.org/wiki/Context-free_language). Because they just answer a yes-or-no question, _how_ that answer is determined is irrelevant; i.e. their execution model is ambiguous. + +Regular expressions were brought into practical applications for text processing and compiler lexers. For searching within text, where the result (including captures) is a portion of the searched text, _how_ a match happened affects the result. Over time, more and more power was needed and "regular expressions" diverged from their formal roots. + +For compiler lexers, especially when implemented as a [discrete compilation phase](https://en.wikipedia.org/wiki/Lexical_analysis), regular expressions were often ingested by a [separate tool](https://en.wikipedia.org/wiki/Flex_(lexical_analyser_generator)) from the rest of the compiler. Understanding formal regular expressions can help clarify the separation of concerns between lexical analysis and parsing. Beyond that, they are less relevant for structuring modern parsers, which interweave error handling and recovery, debuggability, and fine-grained source location tracking across this traditional separation-of-tools. + +The closest formal analogue to what we are proposing are [Parsing Expression Grammars](https://en.wikipedia.org/wiki/Parsing_expression_grammar) ("PEGs"), which describe a recursive descent parser. Our alternation is ordered choice and we support possessive quantification, recursive subpattern calls, and lookahead. However, we are first and foremost providing a regexy presentation: quantification, by default, is non-possessive. + +
+ + +## Motivation + +Imagine processing a bank statement in order to extract transaction details for further scrutiny. Fields are separated by 2-or-more spaces: + +```swift +struct Transaction { + enum Kind { case credit; case debit } + + let kind: Kind + let date: Date + let accountName: String + let amount: Decimal +} + +let statement = """ + CREDIT 03/02/2022 Payroll $200.23 + CREDIT 03/03/2022 Sanctioned Individual A $2,000,000.00 + DEBIT 03/03/2022 Totally Legit Shell Corp $2,000,000.00 + DEBIT 03/05/2022 Beanie Babies Forever $57.33 + """ +``` + +One option is to `split()` around whitespace, hard-coding field offsets for everything except the account name, and `join()`ing the account name fields together to restore their spaces. This carries a lot of downsides such as hard-coded offsets, many unnecessary allocations, and this pattern would not easily expand to supporting other representations. + +Another option is to process an entry in a single pass from left-to-right, but this can get unwieldy: + +```swift +// Parse dates using a simple (localized) numeric strategy +let dateParser = Date.FormatStyle(date: .numeric).parseStrategy + +// Parse currencies as US dollars +let decimalParser = Decimal.FormatStyle.Currency(code: "USD") + +func processEntry(_ s: String) -> Transaction? { + var slice = s[...] + guard let kindEndIdx = slice.firstIndex(of: " "), + let kind = Transaction.Kind(slice[.. Transaction? { + let range = NSRange(line.startIndex..` describes a string processing algorithm. Captures surface the portions of the input that were matched by subpatterns. By convention, capture `0` is the entire match. + +### Creating Regex + +Regexes can be created at run time from a string containing familiar regex syntax. If no output type signature is specified, the regex has type `Regex`, in which captures are existentials and the number of captures is queryable at run time. Alternatively, providing an output type signature produces strongly-typed outputs, where captures are concrete types embedded in a tuple, providing safety and enabling source tools such as code completion. + +```swift +let pattern = #"(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)"# +let regex = try! Regex(compiling: pattern) +// regex: Regex + +let regex: Regex<(Substring, Substring, Substring, Substring, Substring)> = + try! Regex(compiling: pattern) +``` + +*Note*: The syntax accepted and further details on run-time compilation, including `AnyRegexOutput` and extended syntaxes, are discussed in [Run-time Regex Construction][pitches]. + +Type mismatches and invalid regex syntax are diagnosed at construction time by `throw`ing errors. + +When the pattern is known at compile time, regexes can be created from a literal containing the same regex syntax, allowing the compiler to infer the output type. Regex literals enable source tools, e.g. syntax highlighting and actions to refactor into a result builder equivalent. + +```swift +let regex = re'(\w+)\s\s+(\S+)\s\s+((?:(?!\s\s).)*)\s\s+(.*)' +// regex: Regex<(Substring, Substring, Substring, Substring, Substring)> +``` + +*Note*: Regex literals, most notably the choice of delimiter, are discussed in [Regex Literals][pitches]. For this example, I used the less technically-problematic option of `re'...'`. + +This same regex can be created from a result builder, a refactoring-friendly representation: + +```swift +let fieldSeparator = Regex { + CharacterClass.whitespace + OneOrMore(.whitespace) +} + +let regex = Regex { + Capture(OneOrMore(.word)) + fieldSeparator + + Capture(OneOrMore(.whitespace.inverted)) + fieldSeparator + + Capture { + OneOrMore { + NegativeLookahead(fieldSeparator) + CharacterClass.any + } + } + fieldSeparator + + Capture { OneOrMore(.any) } +} +// regex: Regex<(Substring, Substring, Substring, Substring, Substring)> +``` + +*Note*: The result builder API is discussed in [Regex Builders][pitches]. Character classes and other Unicode concerns are discussed in [Unicode for String Processing][pitches]. + +`Regex` itself is a valid component for use inside a result builder, meaning that embedded literals can be used for concision. + +### Using Regex + +A `Regex.Match` contains the result of a match, surfacing captures by number, name, and reference. + +```swift +func processEntry(_ line: String) -> Transaction? { + let regex = re''' + (?x) # Ignore whitespace and comments + (? \w+) \s\s+ + (? \S+) \s\s+ + (? (?: (?!\s\s) . )+) \s\s+ + (? .*) + ''' + // regex: Regex<( + // Substring, + // kind: Substring, + // date: Substring, + // account: Substring, + // amount: Substring + // )> + + guard let match = regex.matchWhole(line), + let kind = Transaction.Kind(match.kind), + let date = try? Date(String(match.date), strategy: dateParser), + let amount = try? Decimal(String(match.amount), format: decimalParser) + else { + return nil + } + + return Transaction( + kind: kind, date: date, account: String(match.account), amount: amount) +} +``` + +*Note*: Details on typed captures using tuple labels are covered in [Regex Literals][pitches]. + +The result builder allows for inline failable value construction, which participates in the overall string processing algorithm: returning `nil` signals a local failure and the engine backtracks to try an alternative. This not only relieves the use site from post-processing, it enables new kinds of processing algorithms, allows for search-space pruning, and enhances debuggability. + +Swift regexes describe an unambiguous algorithm, were choice is ordered and effects can be reliably observed. For example, a `print()` statement inside the `TryCapture`'s transform function will run whenever the overall algorithm naturally dictates an attempt should be made. Optimizations can only elide such calls if they can prove it is behavior-preserving (e.g. "pure"). + +`CustomMatchingRegexComponent`, discussed in [String Processing Algorithms][pitches], allows industrial-strength parsers to be used a regex components. This allows us to drop the overly-permissive pre-parsing step: + +```swift +func processEntry(_ line: String) -> Transaction? { + let fieldSeparator = Regex { + CharacterClass.whitespace + OneOrMore(.whitespace) + } + + // Declare strongly-typed references to store captured values into + let kind = Reference() + let date = Reference() + let account = Reference() + let amount = Reference() + + let regex = Regex { + TryCapture(as: kind) { + OneOrMore(.word) + } transform: { + Transaction.Kind($0) + } + fieldSeparator + + TryCapture(as: date) { dateParser } + fieldSeparator + + Capture(as: account) { + OneOrMore { + NegativeLookahead(fieldSeparator) + CharacterClass.any + } + } + fieldSeparator + + TryCapture(as: amount) { decimalParser } + } + // regex: Regex<(Substring, Transaction.Kind, Date, Substring, Decimal)> + + guard let match = regex.matchWhole(line) else { return nil } + + return Transaction( + kind: match[kind], + date: match[date], + account: String(match[account]), + amount: match[amount]) +} +``` + +*Note*: Details on how references work is discussed in [Regex Builders][pitches]. `Regex.Match` supports referring to _all_ captures by position (`match.1`, etc.) whether named or referenced or neither. Due to compiler limitations, result builders do not support forming labeled tuples for named captures. + + +### Algorithms, algorithms everywhere + +Regexes can be used right out of the box with a variety of powerful and convenient algorithms, including trimming, splitting, and finding/replacing all matches within a string. + +These algorithms are discussed in [String Processing Algorithms][pitches]. + + +### Onward Unicode + +A regex describes an algorithm to be ran over some model of string, and Swift's `String` has a rather unique Unicode-forward model. `Character` is an [extended grapheme cluster](https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) and equality is determined under [canonical equivalence](https://www.unicode.org/reports/tr15/#Canon_Compat_Equivalence). + +Calling `dropFirst()` will not drop a leading byte or `Unicode.Scalar`, but rather a full `Character`. Similarly, a `.` in a regex will match any extended grapheme cluster. A regex will match canonical equivalents by default, strengthening the connection between regex and the equivalent `String` operations. + +Additionally, word boundaries (`\b`) follow [UTS\#29 Word Boundaries](https://www.unicode.org/reports/tr29/#Word_Boundaries), meaning contractions ("don't") and script changes are detected and separated, without incurring significant binary size costs associated with language dictionaries. + +Regex targets [UTS\#18 Level 2](https://www.unicode.org/reports/tr18/#Extended_Unicode_Support) by default, but provides options to switch to scalar-level processing as well as compatibility character classes. Detailed rules on how we infer necessary grapheme cluster breaks inside regexes, as well as options and other concerns, are discussed in [Unicode for String Processing][pitches]. + + +## Detailed design + +```swift +/// A regex represents a string processing algorithm. +public struct Regex { + /// Match a string in its entirety. + /// + /// Returns `nil` if no match and throws on abort + public func matchWhole(_: String) throws -> Match? + + /// Match at the front of a string + /// + /// Returns `nil` if no match and throws on abort + public func matchFront(_: String) throws -> Match? + + /// The result of matching a regex against a string. + @dynamicMemberLookup + public struct Match { + /// The range of the overall match + public let range: Range + + /// The produced output from the match operation + public var output: Output + + /// Lookup a capture by number + public subscript(dynamicMember keyPath: KeyPath) -> T + + /// Lookup a capture by number + @_disfavoredOverload + public subscript( + dynamicMember keyPath: KeyPath<(Output, _doNotUse: ()), Output> + ) -> Output + // Note: this allows `.0` when `Match` is not a tuple. + + } +} +``` + +*Note*: The below are covered by other proposals, but listed here to help round out intuition. + +```swift + +// Result builder interfaces +extension Regex: RegexComponent { + public var regex: Regex { self } + + /// Create a regex out of a single component + public init( + _ content: Content + ) where Content.Output == Output + + /// Result builder interface + public init( + @RegexComponentBuilder _ content: () -> Content + ) where Content.Output == Output + +} +extension Regex.Match { + /// Lookup a capture by reference + public subscript(_ reference: Reference) -> Capture +} + +// Run-time compilation interfaces +extension Regex { + /// Parse and compile `pattern`. + public init(compiling pattern: String, as: Output.Type = Output.self) throws +} +extension Regex where Output == AnyRegexOutput { + /// Parse and compile `pattern`. + public init(compiling pattern: String) throws +} +``` + +### On severability and related proposals + +The proposal split presented is meant to aid focused discussion, while acknowledging that each is interconnected. The boundaries between them are not completely cut-and-dry and could be refined as they enter proposal phase. + +Accepting this proposal in no way implies that all related proposals must be accepted. They are severable and each should stand on their own merit. + + +## Source compatibility + +Everything in this proposal is additive. Regex delimiters may have their own source compatibility impact, which is discussed in that proposal. + +## Effect on ABI stability + +Everything in this proposal is additive. Run-time strings containing regex syntax are represented in the ABI as strings. For this initial release, literals are strings in the ABI as well (they get re-parsed at run time), which avoids baking an intermediate representation into Swift's ABI as we await better static compilation support (see future work). + +## Effect on API resilience + +N/A + +## Alternatives considered + + +### Regular expressions are a blight upon computing! + +"I had one problem so I wrote a regular expression, now I have two problems!" + +Regular expressions have a deservedly mixed reputation, owing to their historical baggage and treatment as a completely separate tool or subsystem. Despite this, they still occupy an important place in string processing. We are proposing the "regexiest regex", allowing them to shine at what they're good at and providing mitigations and off-ramps for their downsides. + +* "Regular expressions are bad because you should use a real parser" + - In other systems, you're either in or you're out, leading to a gravitational pull to stay in when... you should get out + - Our remedy is interoperability with real parsers via `CustomMatchingRegexComponent` + - Literals with refactoring actions provide an incremental off-ramp from regex syntax to result builders and real parsers +* "Regular expressions are bad because ugly unmaintainable syntax" + - We propose literals with source tools support, allowing for better syntax highlighting and analysis + - We propose result builders and refactoring actions from literals into result builders +* "Regular expressions are bad because Unicode" + - We propose a modern Unicode take on regexes + - We treat regexes as algorithms to be ran over some model of String, like's Swift's default Character-based view. +* "Regular expressions are bad because they're not powerful enough" + - Engine is general-purpose enough to support recursive descent parsers with captures, back-references, and lookahead + - We're proposing a regexy presentation on top of more powerful functionality +* "Regular expressions are bad because they're too powerful" + - We provide possessive quantifications, atomic groups, etc., all the normal ways to prune backtracking + - We provide clear semantics of how alternation works as ordered-choice, allowing for understandable execution + - Pathological behavior is ultimately a run-time concern, better handled by engine limiters (future work) + - Optimization is better done as a compiler problem, e.g. static compilation to DFAs (future work) + - Formal treatment of power is better done by other presentations, like PEGs and linear automata (future work) + + + +### Alternative names + +The generic parameter to `Regex` is `Output` and the erased version is `AnyRegexOutput`. This is... fairly generic sounding. + +An alternative could be `Captures`, doubling down on the idea that the entire match is implicitly capture `0`, but that can make describing and understanding how captures combine in the result builder harder to reason through (i.e. a formal distinction between explicit and implicit captures). + +An earlier prototype used the name `Match` for the generic parameter, but that quickly got confusing with all the match methods and was confusing with the result of a match operation (which produces the output, but isn't itself the generic parameter). We think `Match` works better as the result of a match operation. + + +### What's with all the `String(...)` initializer calls at use sites? + +We're working on how to eliminate these, likely by having API to access ranges, slices, or copies of the captured text. + +We're also looking for more community discussion on what the default type system and API presentation should be. As pitched, `Substring` emphasizes that we're referring to slices of the original input, with strong sharing connotations. + +The actual `Match` struct just stores ranges: the `Substrings` are lazily created on demand. This avoids unnecessary ARC traffic and memory usage. + +### Future work: static optimization and compilation + +Swift's support for static compilation is still developing, and future work here is leveraging that to compile regex when profitable. Many regex describe simple [DFAs](https://en.wikipedia.org/wiki/Deterministic_finite_automaton) and can be statically compiled into very efficient programs. Full static compilation needs to be balanced with code size concerns, as a matching-specific bytecode is typically far smaller than a corresponding program (especially since the bytecode interpreter is shared). + +Regex are compiled into an intermediary representation and fairly simple analysis and optimizations are high-value. This compilation currently happens at run time (as such the IR is not ABI), but more of this could happen at compile time to save load/compilation time of the regex itself. Ideally, this representation would be shared along the fully-static compilation path and can be encoded in the ABI as a compact bytecode. + + +### Future work: parser combinators + +What we propose here is an incremental step towards better parsing support in Swift using parser-combinator style libraries. The underlying execution engine supports recursive function calls and mechanisms for library extensibility. `CustomMatchingRegexComponent`'s protocol requirement is effectively a [monadic parser](https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf), meaning `Regex` provides a regex-flavored combinator-like system. + +An issues with traditional parser combinator libraries are the compilation barriers between call-site and definition, resulting in excessive and overly-cautious backtracking traffic. These can be eliminated through better [compilation techniques](https://core.ac.uk/download/pdf/148008325.pdf). As mentioned above, Swift's support for custom static compilation is still under development. + +Future work is a parser combinator system which leverages tiered static compilation and presents a parser-flavored approach, such as limited backtracking by default and more heavily interwoven recursive calls. + + +### Future work: `Regex`-backed enums + +Regexes are often used for tokenization and tokens can be represented with Swift enums. Future language integration could include `Regex` backing somewhat analogous to `RawRepresentable` enums. A Regex-backed enum could conform to `RegexComponent` producing itself upon a match by forming an ordered choice of its cases. + + + +[pitches]: https://github.com/apple/swift-experimental-string-processing/issues/107 diff --git a/Documentation/Evolution/StronglyTypedCaptures.md b/Documentation/Evolution/StronglyTypedCaptures.md index 3bc7194b2..5f3560798 100644 --- a/Documentation/Evolution/StronglyTypedCaptures.md +++ b/Documentation/Evolution/StronglyTypedCaptures.md @@ -9,6 +9,10 @@ Authors: [Richard Wei](https://github.com/rxwei), [Kyle Macomber](https://github - **v2** - Includes entire match in `Regex`'s generic parameter. - Fixes Quantification and Alternation capture types to be consistent with traditional back reference numbering. +- **v3** + - Updates quantifiers to not save the history. + - Updates `capture` method to type `Capture`. + - Adds `Regex.Match` indirection. ## Introduction @@ -20,18 +24,18 @@ let regex = /ab(cd*)(ef)gh/ // => `Regex<(Substring, Substring, Substring)>` // Equivalent result builder syntax: -// let regex = Pattern { +// let regex = Regex { // "ab" -// Group { +// Capture { // "c" -// Repeat("d") -// }.capture() -// "ef".capture() +// ZeroOrMore("d") +// } +// Capture("ef") // "gh" // } -if let match = "abcddddefgh".firstMatch(of: regex) { - print(match) // => ("abcddddefgh", "cdddd", "ef") +if let result = "abcddddefgh".firstMatch(of: regex) { + print(result.match) // => ("abcddddefgh", "cdddd", "ef") } ``` @@ -56,24 +60,24 @@ Across a variety of programming languages, many established regular expression l ## Proposed solution -We introduce a generic structure `Regex` whose generic parameter `Match` includes the match and any captures, using tuples to represent multiple and nested captures. +We introduce a generic structure `Regex` whose generic parameter `Output` includes the match and any captures, using tuples to represent multiple and nested captures. ```swift let regex = /ab(cd*)(ef)gh/ // => Regex<(Substring, Substring, Substring)> -if let match = "abcddddefgh".firstMatch(of: regex) { - print(match) // => ("abcddddefgh", "cdddd", "ef") +if let result = "abcddddefgh".firstMatch(of: regex) { + print(result.match) // => ("abcddddefgh", "cdddd", "ef") } ``` -During type inference for regular expression literals, the compiler infers the type of `Match` from the content of the regular expression. The same will be true for the result builder syntax, except that the type inference rules are expressed as method declarations in the result builder type. +During type inference for regular expression literals, the compiler infers the type of `Output` from the content of the regular expression. The same will be true for the result builder syntax, except that the type inference rules are expressed as method declarations in the result builder type. Because much of the motivation behind providing regex literals in Swift is their familiarity, a top priority of this design is for the result of calling `firstMatch(of:)` with a regex to align with the traditional numbering of backreferences to capture groups, which start at `\1`. ```swift let regex = /ab(cd*)(ef)gh/ -if let match = "abcddddefgh".firstMatch(of: regex) { - print((match.1, match.2)) // => ("cdddd", "ef") +if let result = "abcddddefgh".firstMatch(of: regex) { + print((result.1, result.2)) // => ("cdddd", "ef") } ``` @@ -81,8 +85,8 @@ Quantifiers (`*`, `+`, and `?`) and alternations (`|`) wrap each capture inside ```swift let regex = /ab(?:c(d)*(ef))?gh/ -if let match = "abcddddefgh".firstMatch(of: regex) { - print((match.1, match.2)) // => (Optional(["d","d","d","d"]), Optional("ef")) +if let result = "abcddddefgh".firstMatch(of: regex) { + print((result.1, result.2)) // => (Optional(["d","d","d","d"]), Optional("ef")) } ``` @@ -90,7 +94,7 @@ if let match = "abcddddefgh".firstMatch(of: regex) { ### `Regex` type -`Regex` is a structure that represents a regular expression. `Regex` is generic over an unconstrained generic parameter `Match`. Upon a regex match, the entire match and any captured values are available as part of the result. +`Regex` is a structure that represents a regular expression. `Regex` is generic over an unconstrained generic parameter `Output`. Upon a regex match, the entire match and any captured values are available as part of the result. ```swift public struct Regex: RegexProtocol, ExpressibleByRegexLiteral { @@ -98,7 +102,7 @@ public struct Regex: RegexProtocol, ExpressibleByRegexLiteral { } ``` -> ***Note**: Semantic-level switching (i.e. matching grapheme clusters with canonical equivalence vs Unicode scalar values) is out-of-scope for this pitch, but handling that will likely introduce constraints on `Match`. We use an unconstrained generic parameter in this pitch for brevity and simplicity. The `Substring`s we use for illustration throughout this pitch are created on-the-fly; the actual memory representation uses `Range`. In this sense, the `Match` generic type is just an encoding of the arity and kind of captured content.* +> ***Note**: Semantic-level switching (i.e. matching grapheme clusters with canonical equivalence vs Unicode scalar values) is out-of-scope for this pitch, but handling that will likely introduce constraints on `Output`. We use an unconstrained generic parameter in this pitch for brevity and simplicity. The `Substring`s we use for illustration throughout this pitch are created on-the-fly; the actual memory representation uses `Range`. In this sense, the `Output` generic type is just an encoding of the arity and kind of captured content.* ### `firstMatch(of:)` method @@ -106,7 +110,7 @@ The `firstMatch(of:)` method returns a `Substring` of the first match of the pro ```swift extension String { - public func firstMatch(of regex: R) -> R.Match? + public func firstMatch(of regex: R) -> Regex.Match? } ``` @@ -127,23 +131,23 @@ if let match = line.firstMatch(of: scalarRangePattern) { In this section, we describe the inferred capture types for regular expression patterns and how they compose. -By default, a regular expression literal has type `Regex`. Its generic argument `Match` can be viewed as a tuple of the entire matched substring and any captures. +By default, a regular expression literal has type `Regex`. Its generic argument `Output` can be viewed as a tuple of the entire matched substring and any captures. ```txt -(EntireMatch, Captures...) - ^~~~~~~~~~~ - Capture types +(WholeMatch, Captures...) + ^~~~~~~~~~~ + Capture types ``` -When there are no captures, `Match` is just the entire matched substring, for example: +When there are no captures, `Output` is just the entire matched substring, for example: ```swift let identifier = /[_a-zA-Z]+[_a-zA-Z0-9]*/ // => `Regex` // Equivalent result builder syntax: -// let identifier = Pattern { +// let identifier = Regex { // OneOrMore(/[_a-zA-Z]/) -// Repeat(/[_a-zA-Z0-9]/) +// ZeroOrMore(/[_a-zA-Z0-9]/) // } ``` @@ -158,7 +162,7 @@ let graphemeBreakLowerBound = /([0-9a-fA-F]+)/ // => `Regex<(Substring, Substring)>` // Equivalent result builder syntax: -// let graphemeBreakLowerBound = OneOrMore(.hexDigit).capture() +// let graphemeBreakLowerBound = Capture(OneOrMore(.hexDigit)) ``` #### Concatenation: `abc` @@ -170,8 +174,8 @@ let graphemeBreakLowerBound = /([0-9a-fA-F]+)\.\.[0-9a-fA-F]+/ // => `Regex<(Substring, Substring)>` // Equivalent result builder syntax: -// let graphemeBreakLowerBound = Pattern { -// OneOrMore(.hexDigit).capture() +// let graphemeBreakLowerBound = Regex { +// Capture(OneOrMore(.hexDigit)) // ".." // OneOrMore(.hexDigit) // } @@ -180,10 +184,10 @@ let graphemeBreakRange = /([0-9a-fA-F]+)\.\.([0-9a-fA-F]+)/ // => `Regex<(Substring, Substring, Substring)>` // Equivalent result builder syntax: -// let graphemeBreakRange = Pattern { -// OneOrMore(.hexDigit).capture() +// let graphemeBreakRange = Regex { +// Capture(OneOrMore(.hexDigit)) // ".." -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // } ``` @@ -208,11 +212,11 @@ let graphemeBreakLowerBound = /([0-9a-fA-F]+)(?:\.\.([0-9a-fA-F]+))?/ // => `Regex<(Substring, Substring, Substring?)>` // Equivalent result builder syntax: -// let graphemeBreakLowerBound = Pattern { -// OneOrMore(.hexDigit).capture() +// let graphemeBreakLowerBound = Regex { +// Capture(OneOrMore(.hexDigit)) // Optionally { // ".." -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // } // } ``` @@ -230,21 +234,20 @@ let graphemeBreakPropertyData = /(([0-9a-fA-F]+)(\.\.([0-9a-fA-F]+)))\s*;\s(\w+) // => `Regex<(Substring, Substring, Substring, Substring, Substring, Substring)>` // Equivalent result builder syntax: -// let graphemeBreakPropertyData = Pattern { -// Group { -// OneOrMore(.hexDigit).capture() // (2) -// Group { +// let graphemeBreakPropertyData = Regex { +// Capture { +// Capture(OneOrMore(.hexDigit)) // (2) +// Capture { // ".." -// OneOrMore(.hexDigit).capture() // (4) -// }.capture() // (3) -// }.capture() // (1) +// Capture(OneOrMore(.hexDigit)) // (4) +// } // (3) +// } // (1) // Repeat(.whitespace) // ";" // CharacterClass.whitespace -// OneOrMore(.word).capture() // (5) +// Capture(OneOrMore(.word)) // (5) // Repeat(.any) // } -// .flattened() let input = "007F..009F ; Control" // Match result for `input`: @@ -253,32 +256,32 @@ let input = "007F..009F ; Control" #### Quantification: `*`, `+`, `?`, `{n}`, `{n,}`, `{n,m}` -A quantifier wraps its underlying pattern's capture types in either an `Optional`s or `Array`s. Zero-or-one quantification (`?`) produces an `Optional` and all others produce an `Array`. The kind of quantification, i.e. greedy vs reluctant vs possessive, is irrelevant to determining the capture type. +A quantifier may wrap its underlying pattern's capture types in `Optional`s. Quantifiers whose lower bound is zero produces an `Optional`. The kind of quantification, i.e. greedy vs reluctant vs possessive, is irrelevant to determining the capture type. -| Syntax | Description | Capture type | -| -------------------- | --------------------- | ------------------------------------------------------------- | -| `*` | 0 or more | `Array`s of the sub-pattern capture types | -| `+` | 1 or more | `Array`s of the sub-pattern capture types | -| `?` | 0 or 1 | `Optional`s of the sub-pattern capture types | -| `{n}` | Exactly _n_ | `Array`s of the sub-pattern capture types | -| `{n,m}` | Between _n_ and _m_ | `Array`s of the sub-pattern capture types | -| `{n,}` | _n_ or more | `Array`s of the sub-pattern capture types | +| Syntax | Description | Capture type | +|---------|---------------------|------------------------------------------| +| `*` | 0 or more | `Optional`s of sub-pattern capture types | +| `+` | 1 or more | Sub-pattern capture types | +| `?` | 0 or 1 | `Optional`s of sub-pattern capture types | +| `{n}` | Exactly _n_ | Sub-pattern capture types | +| `{n,m}` | Between _n_ and _m_ | `Optional`s of sub-pattern capture types | +| `{n,}` | _n_ or more | `Optional`s of Sub-pattern capture types | ```swift /([0-9a-fA-F]+)+/ -// => `Regex<(Substring, [Substring])>` +// => `Regex<(Substring, Substring)>` // Equivalent result builder syntax: // OneOrMore { -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // } /([0-9a-fA-F]+)*/ -// => `Regex<(Substring, [Substring])>` +// => `Regex<(Substring, Substring?)>` // Equivalent result builder syntax: -// Repeat { -// OneOrMore(.hexDigit).capture() +// ZeroOrMore { +// Capture(OneOrMore(.hexDigit)) // } /([0-9a-fA-F]+)?/ @@ -286,15 +289,15 @@ A quantifier wraps its underlying pattern's capture types in either an `Optional // Equivalent result builder syntax: // Optionally { -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // } /([0-9a-fA-F]+){3}/ // => `Regex<(Substring, [Substring])>` // Equivalent result builder syntax: -// Repeat(3) { -// OneOrMore(.hexDigit).capture() +// Repeat(count: 3) { +// Capture(OneOrMore(.hexDigit)) // ) /([0-9a-fA-F]+){3,5}/ @@ -302,7 +305,7 @@ A quantifier wraps its underlying pattern's capture types in either an `Optional // Equivalent result builder syntax: // Repeat(3...5) { -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // ) /([0-9a-fA-F]+){3,}/ @@ -310,7 +313,7 @@ A quantifier wraps its underlying pattern's capture types in either an `Optional // Equivalent result builder syntax: // Repeat(3...) { -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // ) let multipleAndNestedOptional = /(([0-9a-fA-F]+)\.\.([0-9a-fA-F]+))?/ @@ -320,35 +323,33 @@ let multipleAndNestedOptional = /(([0-9a-fA-F]+)\.\.([0-9a-fA-F]+))?/ // => `Regex<(Substring, Substring?, Substring?, Substring?)>` // Equivalent result builder syntax: -// let multipleAndNestedOptional = Pattern { -// Optionally { -// OneOrMore(.hexDigit).capture() -// ".." -// OneOrMore(.hexDigit).capture() +// let multipleAndNestedOptional = Regex { +// Capture { +// Optionally { +// Capture(OneOrMore(.hexDigit)) +// ".." +// Capture(OneOrMore(.hexDigit)) +// } // } -// .capture() // } -// .flattened() let multipleAndNestedQuantifier = /(([0-9a-fA-F]+)\.\.([0-9a-fA-F]+))+/ // Positions in result: 0 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 1 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 2 ^~~~~~~~~~~~~~ 3 ^~~~~~~~~~~~~~ -// => `Regex<(Substring, [Substring], [Substring], [Substring])>` +// => `Regex<(Substring, Substring, Substring, Substring)>` // Equivalent result builder syntax: -// let multipleAndNestedQuantifier = Pattern { +// let multipleAndNestedQuantifier = Regex { // OneOrMore { -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // ".." -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // } -// .capture() // } -// .flattened() ``` -Note that capturing collections of repeated captures like this is a departure from most regular expression implementations, which only provide access to the _last_ match of a repeated capture group. For example, Python only captures the last group in this dash-separated string: +Capturing collections of repeated captures like this is consistent with most regular expression implementations, which only provide access to the _last_ match of a repeated capture group. For example, Python only captures the last group in this dash-separated string: ```python rep = re.compile('(?:([0-9a-fA-F]+)-?)+') @@ -357,27 +358,17 @@ print(match.group(1)) # Prints "def0" ``` -By contrast, the proposed Swift version captures all four sub-matches: +Capturing only the last occurrences is the most memory-efficient behavior. For consistency and efficiency, we chose this behavior and its corresponding type. ```swift let pattern = /(?:([0-9a-fA-F]+)-?)+/ -if let match = "1234-5678-9abc-def0".firstMatch(of: pattern) { - print(match.1) +if let result = "1234-5678-9abc-def0".firstMatch(of: pattern) { + print(result.1) } -// Prints ["1234", "5678", "9abc", "def0"] +// Prints "def0" ``` -We believe that the proposed capture behavior is more intuitive. However, the alternative behavior has a smaller memory footprint and is more consistent with usage of backreferences, which only refer to the last match of the repeated capture group: - -```swift -let pattern = /(?:([0-9a-fA-F]+)-?)+ \1/ -var match = "1234-5678-9abc-def0 def0".firstMatch(of: pattern) -print(match != nil) // true -var match = "1234-5678-9abc-def0 1234".firstMatch(of: pattern) -print(match != nil) // false -``` - -As a future direction, we could introduce some way of opting into this behavior. +As a future direction, a way to save the capture history could be useful. We could introduce some way of opting into this behavior. #### Alternation: `a|b` @@ -390,14 +381,13 @@ let numberAlternationRegex = /([01]+)|[0-9]+|([0-9a-fA-F]+)/ // => `Regex<(Substring, Substring?, Substring?)>` // Equivalent result builder syntax: -// let numberAlternationRegex = Pattern { -// OneOf { -// OneOrMore(.binaryDigit).capture() +// let numberAlternationRegex = Regex { +// ChoiceOf { +// Capture(OneOrMore(.binaryDigit)) // OneOrMore(.decimalDigit) -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // } // } -// .flattened() let scalarRangeAlternation = /([0-9a-fA-F]+)\.\.([0-9a-fA-F]+)|([0-9a-fA-F]+)/ // Positions in result: 0 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -406,17 +396,16 @@ let scalarRangeAlternation = /([0-9a-fA-F]+)\.\.([0-9a-fA-F]+)|([0-9a-fA-F]+)/ // => `Regex<(Substring, Substring?, Substring?, Substring?)> // Equivalent result builder syntax: -// let scalarRangeAlternation = Pattern { -// OneOf { -// Group { -// OneOrMore(.hexDigit).capture() +// let scalarRangeAlternation = Regex { +// ChoiceOf { +// Capture { +// Capture(OneOrMore(.hexDigit)) // ".." -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // } -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // } // } -// .flattened() let nestedScalarRangeAlternation = /(([0-9a-fA-F]+)\.\.([0-9a-fA-F]+))|([0-9a-fA-F]+)/ // Positions in result: 0 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -426,19 +415,55 @@ let nestedScalarRangeAlternation = /(([0-9a-fA-F]+)\.\.([0-9a-fA-F]+))|([0-9a-fA // => `Regex<(Substring, Substring?, Substring?, Substring?, Substring?)> // Equivalent result builder syntax: -// let scalarRangeAlternation = Pattern { -// OneOf { -// Group { -// OneOrMore(.hexDigit).capture() +// let scalarRangeAlternation = Regex { +// ChoiceOf { +// Capture { +// ChoiceOf(OneOrMore(.hexDigit)) // ".." -// OneOrMore(.hexDigit).capture() +// ChoiceOf(OneOrMore(.hexDigit)) // } -// .capture() -// -// OneOrMore(.hexDigit).capture() +// Capture(OneOrMore(.hexDigit)) // } // } -// .flattened() +``` + +### Dynamic captures + +So far, we have explored offering static capture types for using a regular expression that is available in source code. Meanwhile, we would like to apply Swift's string processing capabilities to fully dynamic use cases, such as matching a string using a regular expression obtained at runtime. + +To support dynamism, we introduce a new type, `AnyRegexOutput` that represents a tree of captures, and add a `Regex` initializer that accepts a string and produces `Regex`. `AnyRegexOutput` can also be used to retrofit regexes with strongly typed captures to preexisting use sites of `Regex`. + +```swift +public struct AnyRegexOutput: Equatable, RandomAccessCollection { + public var match: Substring? { get } + public var range: Range { get } + public var count: Int { get } + public subscript(name: String) -> Substring { get } + public subscript(position: Int) -> Substring { get } + ... +} + +extension Regex.Match where Output == AnyRegexOutput { + /// Creates a regex dynamically from text. + public init(_ text: String) throws where Output == AnyRegexOutput + + /// Creates a type-erased match from an existing one. + public init(_ other: Regex.Match) +} +``` + +Example usage: + +```swift +let regex = readLine()! // (\w*)(\d)+(\w*)? +let input = readLine()! // abcd1234xyz +print(input.firstMatch(of: regex)?) +// [ +// "abcd1234xyz" +// "abcd", +// "4", +// .some("xyz") +// ] ``` ## Effect on ABI stability @@ -480,7 +505,7 @@ For exact-count quantifications, e.g. `[a-z]{5}`, it would slightly improve type However, this would cause an inconsistency between exact-count quantification and bounded quantification. We believe that the proposed design will result in fewer surprises as we associate the `{...}` quantifier syntax with `Array`. -### `Regex` instead of `Regex` +### `Regex` instead of `Regex` In the initial version of this pitch, `Regex` was _only_ generic over its captures and `firstMatch(of:)` was responsible for flattening together the match and captures into a tuple. @@ -555,8 +580,8 @@ It's possible to derive the flat type from the structured type (but not vice ver ```swift extension String { struct MatchResult { - var flat: R.Match.Flat { get } - var structured: R.Match { get } + var flat: R.Output.Flat { get } + var structured: R.Output { get } } func firstMatch(of regex: R) -> MatchResult? } @@ -565,42 +590,3 @@ extension String { This is cool, but it adds extra complexity to `Regex` and it isn't as clear because the generic type no longer aligns with the traditional regex backreference numbering. Because the primary motivation for providing regex literals in Swift is their familiarity, we think the consistency of the flat capture types trumps the added safety and ergonomics of the structured capture types. We think the calculus probably flips in favor of a structured capture types for the result builder syntax, for which familiarity is not as high a priority. - -## Future directions - -### Dynamic captures - -So far, we have explored offering static capture types for using a regular expression that is available in source code. Meanwhile, we would like to apply Swift's string processing capabilities to fully dynamic use cases, such as matching a string using a regular expression obtained at runtime. - -To support dynamism, we could introduce a new type, `DynamicCaptures` that represents a tree of captures, and add a `Regex` initializer that accepts a string and produces `Regex<(Substring, DynamicCaptures)>`. - -```swift -public struct DynamicCaptures: Equatable, RandomAccessCollection { - var range: Range { get } - var substring: Substring? { get } - subscript(name: String) -> DynamicCaptures { get } - subscript(position: Int) -> DynamicCaptures { get } -} - -extension Regex where Match == (Substring, DynamicCaptures) { - public init(_ string: String) throws -} -``` - -Example usage: - -```swift -let regex = readLine()! // (\w*)(\d)+z(\w*)? -let input = readLine()! // abcd1234xyz -print(input.firstMatch(of: regex)?.1) -// [ -// "abcd", -// [ -// "1", -// "2", -// "3", -// "4", -// ], -// .some("xyz") -// ] -``` diff --git a/README.md b/README.md index 941231b24..69c545243 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ See [Declarative String Processing Overview][decl-string] ## Requirements -- [Swift Trunk Development Snapshot](https://www.swift.org/download/#snapshots) DEVELOPMENT-SNAPSHOT-2022-02-03 or later. +- [Swift Trunk Development Snapshot](https://www.swift.org/download/#snapshots) DEVELOPMENT-SNAPSHOT-2022-03-09 or later. ## Integration with Swift @@ -45,8 +45,9 @@ A pair of corresponding branches are expected to build successfully together and To integrate the latest changes in apple/swift-experimental-string-processing to apple/swift, carefully follow the workflow: - Create pull requests. - - Create a pull request in apple/swift-experimental-string-processing from `main` to `swift/main`, e.g. "[Integration] main -> swift/main". - - If apple/swift needs to be modified to work with the latest `main` in apple/swift-experimental-string-processing, create a pull request in apple/swift. + - Create a branch from a commit on `main` that you would like to integrate into `swift/main`. + - Create a pull request in apple/swift-experimental-string-processing from that branch to `swift/main`, e.g. "[Integration] main () -> swift/main". + - If apple/swift needs to be modified to work with the latest `main` in apple/swift-experimental-string-processing, create a pull request in apple/swift. **Note:** Since CI in apple/swift-experimental-string-processing has not yet been set up to run full toolchain tests, you should create a PR in apple/swift regardless; if the integartion does not require changing apple/swift, create a dummy PR in apple/swift by changing the README and just not merge it in the end. - Trigger CI. - In the apple/swift-experimental-string-processing pull request, trigger CI using the following command (replacing `` with the apple/swift pull request number, if any): ``` diff --git a/Sources/Exercises/Participants/RegexParticipant.swift b/Sources/Exercises/Participants/RegexParticipant.swift index 635e0bcf9..bae3aed42 100644 --- a/Sources/Exercises/Participants/RegexParticipant.swift +++ b/Sources/Exercises/Participants/RegexParticipant.swift @@ -58,11 +58,11 @@ private func extractFromCaptures( } @inline(__always) // get rid of generic please -private func graphemeBreakPropertyData( +private func graphemeBreakPropertyData( forLine line: String, using regex: RP -) -> GraphemeBreakEntry? where RP.Match == (Substring, Substring, Substring?, Substring) { - line.match(regex).map(\.match).flatMap(extractFromCaptures) +) -> GraphemeBreakEntry? where RP.Output == (Substring, Substring, Substring?, Substring) { + line.match(regex).map(\.output).flatMap(extractFromCaptures) } private func graphemeBreakPropertyDataLiteral( @@ -80,18 +80,18 @@ private func graphemeBreakPropertyData( forLine line: String ) -> GraphemeBreakEntry? { line.match { - tryCapture(oneOrMore(.hexDigit)) { Unicode.Scalar(hex: $0) } - optionally { + TryCapture(OneOrMore(.hexDigit)) { Unicode.Scalar(hex: $0) } + Optionally { ".." - tryCapture(oneOrMore(.hexDigit)) { Unicode.Scalar(hex: $0) } + TryCapture(OneOrMore(.hexDigit)) { Unicode.Scalar(hex: $0) } } - oneOrMore(.whitespace) + OneOrMore(.whitespace) ";" - oneOrMore(.whitespace) - tryCapture(oneOrMore(.word)) { Unicode.GraphemeBreakProperty($0) } - zeroOrMore(.any) + OneOrMore(.whitespace) + TryCapture(OneOrMore(.word)) { Unicode.GraphemeBreakProperty($0) } + ZeroOrMore(.any) }.map { - let (_, lower, upper, property) = $0.match + let (_, lower, upper, property) = $0.output return GraphemeBreakEntry(lower...(upper ?? lower), property) } } diff --git a/Sources/Prototypes/TourOfTypes/Literal.swift b/Sources/Prototypes/TourOfTypes/Literal.swift index 17b95856b..e5cec19a1 100644 --- a/Sources/Prototypes/TourOfTypes/Literal.swift +++ b/Sources/Prototypes/TourOfTypes/Literal.swift @@ -55,16 +55,16 @@ enum SemanticsLevel { } /// Conformers can be ran as a regex / pattern -protocol RegexProtocol { +protocol RegexComponent { var level: SemanticsLevel? { get } } /// Provide the option to encode semantic level statically protocol RegexLiteralProtocol: ExpressibleByRegexLiteral { - associatedtype ScalarSemanticRegex: RegexProtocol - associatedtype GraphemeSemanticRegex: RegexProtocol - associatedtype POSIXSemanticRegex: RegexProtocol - associatedtype UnspecifiedSemanticRegex: RegexProtocol = RegexLiteral + associatedtype ScalarSemanticRegex: RegexComponent + associatedtype GraphemeSemanticRegex: RegexComponent + associatedtype POSIXSemanticRegex: RegexComponent + associatedtype UnspecifiedSemanticRegex: RegexComponent = RegexLiteral var scalarSemantic: ScalarSemanticRegex { get } var graphemeSemantic: GraphemeSemanticRegex { get } @@ -84,16 +84,16 @@ struct StaticSemanticRegexLiteral: RegexLiteralProtocol { */ /// A regex that has statically bound its semantic level - struct ScalarSemanticRegex: RegexProtocol { + struct ScalarSemanticRegex: RegexComponent { var level: SemanticsLevel? { .scalar } } - struct GraphemeSemanticRegex: RegexProtocol { + struct GraphemeSemanticRegex: RegexComponent { var level: SemanticsLevel? { .graphemeCluster } } - struct POSIXSemanticRegex: RegexProtocol { + struct POSIXSemanticRegex: RegexComponent { var level: SemanticsLevel? { .posix } } - struct UnspecifiedSemanticRegex: RegexProtocol { + struct UnspecifiedSemanticRegex: RegexComponent { var level: SemanticsLevel? { nil } } @@ -132,9 +132,9 @@ struct RegexLiteral: ExpressibleByRegexLiteral { } } -extension RegexLiteral: RegexProtocol, RegexLiteralProtocol { +extension RegexLiteral: RegexComponent, RegexLiteralProtocol { /// A regex that has finally bound its semantic level (dynamically) - struct BoundSemantic: RegexProtocol { + struct BoundSemantic: RegexComponent { var _level: SemanticsLevel // Bound semantic level var level: SemanticsLevel? { _level } } diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index 312ea9a97..683d45e6e 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -89,12 +89,13 @@ struct StandardErrorStream: TextOutputStream { var standardError = StandardErrorStream() typealias Counter = Int64 -let regexProtocolName = "RegexProtocol" -let matchAssociatedTypeName = "Match" -let patternBuilderTypeName = "RegexBuilder" +let regexComponentProtocolName = "RegexComponent" +let outputAssociatedTypeName = "Output" let patternProtocolRequirementName = "regex" let regexTypeName = "Regex" let baseMatchTypeName = "Substring" +let concatBuilderName = "RegexComponentBuilder" +let altBuilderName = "AlternationBuilder" @main struct VariadicsGenerator: ParsableCommand { @@ -135,14 +136,14 @@ struct VariadicsGenerator: ParsableCommand { emitConcatenation(leftArity: leftArity, rightArity: rightArity) } - for arity in 0..( - combining next: R1, into combined: R0 + public static func buildPartialBlock<\(genericParams)>( + accumulated: R0, next: R1 ) -> \(regexTypeName)<\(matchType)> \(whereClause) { - .init(node: combined.regex.root.appending(next.regex.root)) + .init(node: accumulated.regex.root.appending(next.regex.root)) } } @@ -246,15 +247,15 @@ struct VariadicsGenerator: ParsableCommand { func emitConcatenationWithEmpty(leftArity: Int) { // T + () = T output(""" - extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 + , R0: \(regexComponentProtocolName), R1: \(regexComponentProtocolName)>( + accumulated: R0, next: R1 ) -> \(regexTypeName)< """) if leftArity == 0 { @@ -266,7 +267,7 @@ struct VariadicsGenerator: ParsableCommand { } output(")") } - output("> where R0.\(matchAssociatedTypeName) == ") + output("> where R0.\(outputAssociatedTypeName) == ") if leftArity == 0 { output("W0") } else { @@ -278,7 +279,7 @@ struct VariadicsGenerator: ParsableCommand { } output(""" { - .init(node: combined.regex.root.appending(next.regex.root)) + .init(node: accumulated.regex.root.appending(next.regex.root)) } } @@ -286,9 +287,9 @@ struct VariadicsGenerator: ParsableCommand { } enum QuantifierKind: String, CaseIterable { - case zeroOrOne = "optionally" - case zeroOrMore = "zeroOrMore" - case oneOrMore = "oneOrMore" + case zeroOrOne = "Optionally" + case zeroOrMore = "ZeroOrMore" + case oneOrMore = "OneOrMore" var operatorName: String { switch self { @@ -310,14 +311,15 @@ struct VariadicsGenerator: ParsableCommand { struct QuantifierParameters { var disfavored: String var genericParams: String + var whereClauseForInit: String var whereClause: String var quantifiedCaptures: String var matchType: String var repeatingWhereClause: String { - whereClause.isEmpty + whereClauseForInit.isEmpty ? "where R.Bound == Int" - : whereClause + ", R.Bound == Int" + : whereClauseForInit + ", R.Bound == Int" } init(kind: QuantifierKind, arity: Int) { @@ -329,14 +331,12 @@ struct VariadicsGenerator: ParsableCommand { result += (0..= 0) let params = QuantifierParameters(kind: kind, arity: arity) output(""" - \(params.disfavored)\ - public func \(kind.rawValue)<\(params.genericParams)>( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly - ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { - .init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component.regex.root)) + extension \(kind.rawValue) { + \(params.disfavored)\ + public init<\(params.genericParams)>( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) \(params.whereClauseForInit) { + self.init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component.regex.root)) + } } - \(params.disfavored)\ - public func \(kind.rawValue)<\(params.genericParams)>( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component - ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { - .init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component().regex.root)) + extension \(kind.rawValue) { + \(params.disfavored)\ + public init<\(params.genericParams)>( + _ behavior: QuantificationBehavior = .eagerly, + @\(concatBuilderName) _ component: () -> Component + ) \(params.whereClauseForInit) { + self.init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component().regex.root)) + } } \(params.disfavored)\ public postfix func \(kind.operatorName)<\(params.genericParams)>( _ component: Component - ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { + ) -> \(kind.rawValue)<\(params.matchType)> \(params.whereClause) { .init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component.regex.root)) } \(kind == .zeroOrOne ? """ - extension RegexBuilder { + extension \(concatBuilderName) { public static func buildLimitedAvailability<\(params.genericParams)>( _ component: Component ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { @@ -400,42 +408,44 @@ struct VariadicsGenerator: ParsableCommand { // We would need to prohibit `repeat(count: 0)`; can only happen at runtime output(""" - \(params.disfavored)\ - public func repeating<\(params.genericParams)>( - _ component: Component, - count: Int - ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) - } + extension Repeat { + \(params.disfavored)\ + public init<\(params.genericParams)>( + _ component: Component, + count: Int + ) \(params.whereClauseForInit) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } - \(params.disfavored)\ - public func repeating<\(params.genericParams)>( - count: Int, - @RegexBuilder _ component: () -> Component - ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) - } - - \(params.disfavored)\ - public func repeating<\(params.genericParams), R: RangeExpression>( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly - ) -> \(regexTypeName)<\(params.matchType)> \(params.repeatingWhereClause) { - .init(node: .repeating(expression.relative(to: 0..( + count: Int, + @\(concatBuilderName) _ component: () -> Component + ) \(params.whereClauseForInit) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } - \(params.disfavored)\ - public func repeating<\(params.genericParams), R: RangeExpression>( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component - ) -> \(regexTypeName)<\(params.matchType)> \(params.repeatingWhereClause) { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) \(params.repeatingWhereClause) { + self.init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @\(concatBuilderName) _ component: () -> Component + ) \(params.repeatingWhereClause) { + self.init(node: .repeating(expression.relative(to: 0.. 0 { - result += ", R0.\(matchAssociatedTypeName) == (W0, \((0.. 0 { - result += ", R1.\(matchAssociatedTypeName) == (W1, \((leftArity..( - combining next: R1, into combined: R0 - ) -> \(regexTypeName)<\(matchType)> \(whereClause) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + extension \(altBuilderName) { + public static func buildPartialBlock<\(genericParams)>( + accumulated: R0, next: R1 + ) -> ChoiceOf<\(matchType)> \(whereClause) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } - public func | <\(genericParams)>(lhs: R0, rhs: R1) -> \(regexTypeName)<\(matchType)> \(whereClause) { + public func | <\(genericParams)>(lhs: R0, rhs: R1) -> ChoiceOf<\(matchType)> \(whereClause) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } @@ -505,14 +515,14 @@ struct VariadicsGenerator: ParsableCommand { return "R, W, " + captures }() let whereClause: String = """ - where R: \(regexProtocolName), \ - R.\(matchAssociatedTypeName) == (W, \(captures)) + where R: \(regexComponentProtocolName), \ + R.\(outputAssociatedTypeName) == (W, \(captures)) """ let resultCaptures = (0..(_ regex: R) -> \(regexTypeName)<(W, \(resultCaptures))> \(whereClause) { - .init(node: .alternation([regex.regex.root])) + extension \(altBuilderName) { + public static func buildPartialBlock<\(genericParams)>(first regex: R) -> ChoiceOf<(W, \(resultCaptures))> \(whereClause) { + .init(node: .orderedChoice([regex.regex.root])) } } @@ -520,9 +530,10 @@ struct VariadicsGenerator: ParsableCommand { } func emitCapture(arity: Int) { + let disfavored = arity == 0 ? "@_disfavoredOverload\n" : "" let genericParams = arity == 0 - ? "R: \(regexProtocolName), W" - : "R: \(regexProtocolName), W, " + (0..( - _ component: R - ) -> \(regexTypeName)<\(rawNewMatchType)> \(whereClause) { - .init(node: .group(.capture, component.regex.root)) - } + extension Capture { + \(disfavored)\ + public init<\(genericParams)>( + _ component: R + ) \(whereClauseRaw) { + self.init(node: .capture(component.regex.root)) + } - public func capture<\(genericParams)>( - _ component: R, as reference: Reference - ) -> \(regexTypeName)<\(rawNewMatchType)> \(whereClause) { - .init(node: .group(.capture, component.regex.root, reference.id)) - } + \(disfavored)\ + public init<\(genericParams)>( + _ component: R, as reference: Reference + ) \(whereClauseRaw) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } - public func capture<\(genericParams), NewCapture>( - _ component: R, - transform: @escaping (Substring) -> NewCapture - ) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) - } + \(disfavored)\ + public init<\(genericParams), NewCapture>( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) \(whereClauseTransformed) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } - public func capture<\(genericParams), NewCapture>( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture - ) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) + \(disfavored)\ + public init<\(genericParams), NewCapture>( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) \(whereClauseTransformed) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } } - public func tryCapture<\(genericParams), NewCapture>( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture - ) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) - } + extension TryCapture { + \(disfavored)\ + public init<\(genericParams), NewCapture>( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) \(whereClauseTransformed) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } - public func tryCapture<\(genericParams), NewCapture>( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture - ) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) - } + \(disfavored)\ + public init<\(genericParams), NewCapture>( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) \(whereClauseTransformed) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } - public func tryCapture<\(genericParams), NewCapture>( - _ component: R, - transform: @escaping (Substring) -> NewCapture? - ) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) - } + \(disfavored)\ + public init<\(genericParams), NewCapture>( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) \(whereClauseTransformed) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } - public func tryCapture<\(genericParams), NewCapture>( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? - ) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) + \(disfavored)\ + public init<\(genericParams), NewCapture>( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) \(whereClauseTransformed) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity \(arity) - public func capture<\(genericParams)>( - @RegexBuilder _ component: () -> R - ) -> \(regexTypeName)<\(rawNewMatchType)> \(whereClause) { - .init(node: .group(.capture, component().regex.root)) - } + extension Capture { + \(disfavored)\ + public init<\(genericParams)>( + @\(concatBuilderName) _ component: () -> R + ) \(whereClauseRaw) { + self.init(node: .capture(component().regex.root)) + } - public func capture<\(genericParams)>( - as reference: Reference, - @RegexBuilder _ component: () -> R - ) -> \(regexTypeName)<\(rawNewMatchType)> \(whereClause) { - .init(node: .group(.capture, component().regex.root, reference.id)) - } + \(disfavored)\ + public init<\(genericParams)>( + as reference: Reference, + @\(concatBuilderName) _ component: () -> R + ) \(whereClauseRaw) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } - public func capture<\(genericParams), NewCapture>( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture - ) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) - } + \(disfavored)\ + public init<\(genericParams), NewCapture>( + @\(concatBuilderName) _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) \(whereClauseTransformed) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } - public func tryCapture<\(genericParams), NewCapture>( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture - ) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) + \(disfavored)\ + public init<\(genericParams), NewCapture>( + as reference: Reference, + @\(concatBuilderName) _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) \(whereClauseTransformed) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } } - public func tryCapture<\(genericParams), NewCapture>( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? - ) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) - } + extension TryCapture { + \(disfavored)\ + public init<\(genericParams), NewCapture>( + @\(concatBuilderName) _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) \(whereClauseTransformed) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + \(disfavored)\ + public init<\(genericParams), NewCapture>( + as reference: Reference, + @\(concatBuilderName) _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) \(whereClauseTransformed) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } - public func tryCapture<\(genericParams), NewCapture>( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? - ) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) + \(disfavored)\ + public init<\(genericParams), NewCapture>( + @\(concatBuilderName) _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) \(whereClauseTransformed) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + \(disfavored)\ + public init<\(genericParams), NewCapture>( + as reference: Reference, + @\(concatBuilderName) _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) \(whereClauseTransformed) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } diff --git a/Sources/_MatchingEngine/Regex/Parse/CaptureStructure.swift b/Sources/_MatchingEngine/Regex/Parse/CaptureStructure.swift index 7faf4f5ff..8298dc207 100644 --- a/Sources/_MatchingEngine/Regex/Parse/CaptureStructure.swift +++ b/Sources/_MatchingEngine/Regex/Parse/CaptureStructure.swift @@ -59,54 +59,29 @@ extension CaptureStructure.Constructor { } public mutating func grouping( - _ child: T, as kind: AST.Group.Kind + _ child: T, + as kind: AST.Group.Kind ) -> CaptureStructure { - let innerCaptures = child._captureStructure(&self) switch kind { case .capture: - return .atom() + innerCaptures + return capturing(child) case .namedCapture(let name): - return .atom(name: name.value) + innerCaptures + return capturing(name: name.value, child) case .balancedCapture(let b): - return .atom(name: b.name?.value) + innerCaptures + return capturing(name: b.name?.value, child) default: precondition(!kind.isCapturing) - return innerCaptures - } - } - - public mutating func grouping( - _ child: T, - as kind: AST.Group.Kind, - withTransform transform: CaptureTransform - ) -> CaptureStructure { - let innerCaptures = child._captureStructure(&self) - switch kind { - case .capture: - return .atom(type: AnyType(transform.resultType)) + innerCaptures - case .namedCapture(let name): - return .atom(name: name.value, type: AnyType(transform.resultType)) - + innerCaptures - default: - return innerCaptures + return child._captureStructure(&self) } } - public mutating func grouping( + public mutating func capturing( + name: String? = nil, _ child: T, - as kind: AST.Group.Kind, - withType type: AnyType + withType type: AnyType? = nil ) -> CaptureStructure { - let innerCaptures = child._captureStructure(&self) - switch kind { - case .capture: - return .atom(type: type) + innerCaptures - case .namedCapture(let name): - return .atom(name: name.value, type: type) - + innerCaptures - default: - return innerCaptures - } + .atom(name: name, type: type) + + child._captureStructure(&self) } // TODO: We'll likely want/need a generalization of diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift index 03e2c53ee..dbe7923ec 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift @@ -40,7 +40,7 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func contains(_ regex: R) -> Bool { + public func contains(_ regex: R) -> Bool { contains(RegexConsumer(regex)) } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index 64a5eb943..40d5b9950 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -56,11 +56,11 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func firstRange(of regex: R) -> Range? { + public func firstRange(of regex: R) -> Range? { firstRange(of: RegexConsumer(regex)) } - public func lastRange(of regex: R) -> Range? { + public func lastRange(of regex: R) -> Range? { lastRange(of: RegexConsumer(regex)) } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift index aefdbce3f..e56e35e72 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift @@ -216,13 +216,13 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func ranges( + public func ranges( of regex: R ) -> RangesCollection> { ranges(of: RegexConsumer(regex)) } - public func rangesFromBack( + public func rangesFromBack( of regex: R ) -> ReversedRangesCollection> { rangesFromBack(of: RegexConsumer(regex)) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift index 36a28b381..e2c9d78a4 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift @@ -149,7 +149,7 @@ extension RangeReplaceableCollection // MARK: Regex algorithms extension RangeReplaceableCollection where SubSequence == Substring { - public func replacing( + public func replacing( _ regex: R, with replacement: Replacement, subrange: Range, @@ -162,7 +162,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: maxReplacements) } - public func replacing( + public func replacing( _ regex: R, with replacement: Replacement, maxReplacements: Int = .max @@ -174,7 +174,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: maxReplacements) } - public mutating func replace( + public mutating func replace( _ regex: R, with replacement: Replacement, maxReplacements: Int = .max diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index ba2cda30b..15c946ca2 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -275,13 +275,13 @@ extension BidirectionalCollection where Element: Comparable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func split( + public func split( by separator: R ) -> SplitCollection> { split(by: RegexConsumer(separator)) } - public func splitFromBack( + public func splitFromBack( by separator: R ) -> ReversedSplitCollection> { splitFromBack(by: RegexConsumer(separator)) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift index ee9432fb4..75c6e1133 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift @@ -48,11 +48,11 @@ extension BidirectionalCollection where Element: Equatable { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func starts(with regex: R) -> Bool { + public func starts(with regex: R) -> Bool { starts(with: RegexConsumer(regex)) } - public func ends(with regex: R) -> Bool { + public func ends(with regex: R) -> Bool { ends(with: RegexConsumer(regex)) } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index b2438bb3b..65a71e1b7 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -257,15 +257,15 @@ extension RangeReplaceableCollection // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func trimmingPrefix(_ regex: R) -> SubSequence { + public func trimmingPrefix(_ regex: R) -> SubSequence { trimmingPrefix(RegexConsumer(regex)) } - public func trimmingSuffix(_ regex: R) -> SubSequence { + public func trimmingSuffix(_ regex: R) -> SubSequence { trimmingSuffix(RegexConsumer(regex)) } - public func trimming(_ regex: R) -> SubSequence { + public func trimming(_ regex: R) -> SubSequence { trimming(RegexConsumer(regex)) } } @@ -273,15 +273,15 @@ extension BidirectionalCollection where SubSequence == Substring { extension RangeReplaceableCollection where Self: BidirectionalCollection, SubSequence == Substring { - public mutating func trimPrefix(_ regex: R) { + public mutating func trimPrefix(_ regex: R) { trimPrefix(RegexConsumer(regex)) } - public mutating func trimSuffix(_ regex: R) { + public mutating func trimSuffix(_ regex: R) { trimSuffix(RegexConsumer(regex)) } - public mutating func trim(_ regex: R) { + public mutating func trim(_ regex: R) { let consumer = RegexConsumer(regex) trimPrefix(consumer) trimSuffix(consumer) @@ -289,15 +289,15 @@ extension RangeReplaceableCollection } extension Substring { - public mutating func trimPrefix(_ regex: R) { + public mutating func trimPrefix(_ regex: R) { trimPrefix(RegexConsumer(regex)) } - public mutating func trimSuffix(_ regex: R) { + public mutating func trimSuffix(_ regex: R) { trimSuffix(RegexConsumer(regex)) } - public mutating func trim(_ regex: R) { + public mutating func trim(_ regex: R) { let consumer = RegexConsumer(regex) trimPrefix(consumer) trimSuffix(consumer) diff --git a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift index 5af689cbc..4dac3cef5 100644 --- a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift +++ b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift @@ -10,7 +10,7 @@ //===----------------------------------------------------------------------===// public struct RegexConsumer< - R: RegexProtocol, Consumed: BidirectionalCollection + R: RegexComponent, Consumed: BidirectionalCollection > where Consumed.SubSequence == Substring { // TODO: Should `Regex` itself implement these protocols? let regex: R @@ -28,7 +28,7 @@ extension RegexConsumer { consumed.base, in: range, mode: .partialFromFront ) else { return nil } - return (result.range.upperBound, result.match) + return (result.range.upperBound, result.output) } } @@ -36,7 +36,7 @@ extension RegexConsumer { // well, taking advantage of the fact that the captures can be ignored extension RegexConsumer: MatchingCollectionConsumer { - public typealias Match = R.Match + public typealias Match = R.Output public func matchingConsuming( _ consumed: Consumed, in range: Range diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index 91d33e123..c0699b805 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -38,13 +38,13 @@ extension BidirectionalCollection { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func firstMatch( + public func firstMatch( of regex: R ) -> _MatchResult>? { firstMatch(of: RegexConsumer(regex)) } - public func lastMatch( + public func lastMatch( of regex: R ) -> _BackwardMatchResult>? { lastMatch(of: RegexConsumer(regex)) diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index 2feb09df0..f99e525b5 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -75,7 +75,7 @@ extension RangeReplaceableCollection { // MARK: Regex algorithms extension RangeReplaceableCollection where SubSequence == Substring { - public func replacing( + public func replacing( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, subrange: Range, @@ -88,7 +88,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: maxReplacements) } - public func replacing( + public func replacing( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, maxReplacements: Int = .max @@ -100,7 +100,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { maxReplacements: maxReplacements) } - public mutating func replace( + public mutating func replace( _ regex: R, with replacement: (_MatchResult>) throws -> Replacement, maxReplacements: Int = .max diff --git a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift index f92c353ea..1e4dae113 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift @@ -184,13 +184,13 @@ extension BidirectionalCollection { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - public func matches( + public func matches( of regex: R ) -> MatchesCollection> { matches(of: RegexConsumer(regex)) } - public func matchesFromBack( + public func matchesFromBack( of regex: R ) -> ReversedMatchesCollection> { matchesFromBack(of: RegexConsumer(regex)) diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index d6389c1f6..c9599b925 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -299,31 +299,33 @@ extension Compiler.ByteCodeGen { } } - mutating func emitGroup( - _ kind: AST.Group.Kind, + mutating func emitTransform( + _ t: CaptureTransform, _ child: DSLTree.Node, - _ referenceID: ReferenceID? - ) throws -> CaptureRegister? { - guard kind.isCapturing || referenceID == nil else { - throw Unreachable("Reference ID shouldn't exist for non-capturing groups") + into cap: CaptureRegister + ) throws { + let transform = builder.makeTransformFunction { + input, range in + t(input[range]) } + builder.buildBeginCapture(cap) + try emitNode(child) + builder.buildEndCapture(cap) + builder.buildTransformCapture(cap, transform) + } + + mutating func emitNoncapturingGroup( + _ kind: AST.Group.Kind, + _ child: DSLTree.Node + ) throws { + assert(!kind.isCapturing) options.beginScope() defer { options.endScope() } - // If we have a strong type, write result directly into - // the capture register. - // - // FIXME: Unify with .groupTransform - if kind.isCapturing, case let .matcher(_, m) = child { - let cap = builder.makeCapture(id: referenceID) - emitMatcher(m, into: cap) - return cap - } - if let lookaround = kind.lookaroundKind { try emitLookaround(lookaround, child) - return nil + return } switch kind { @@ -331,22 +333,16 @@ extension Compiler.ByteCodeGen { .lookbehind, .negativeLookbehind: throw Unreachable("TODO: reason") - case .capture, .namedCapture: - let cap = builder.makeCapture(id: referenceID) - builder.buildBeginCapture(cap) - try emitNode(child) - builder.buildEndCapture(cap) - return cap + case .capture, .namedCapture, .balancedCapture: + throw Unreachable("These should produce a capture node") case .changeMatchingOptions(let optionSequence, _): options.apply(optionSequence) try emitNode(child) - return nil default: // FIXME: Other kinds... try emitNode(child) - return nil } } @@ -557,7 +553,7 @@ extension Compiler.ByteCodeGen { mutating func emitNode(_ node: DSLTree.Node) throws { switch node { - case let .alternation(children): + case let .orderedChoice(children): try emitAlternation(children) case let .concatenation(children): @@ -565,8 +561,21 @@ extension Compiler.ByteCodeGen { try emitConcatenationComponent(child) } - case let .group(kind, child, referenceID): - _ = try emitGroup(kind, child, referenceID) + case let .capture(_, refId, child): + let cap = builder.makeCapture(id: refId) + 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) + } + + case let .nonCapturingGroup(kind, child): + try emitNoncapturingGroup(kind, child) case .conditional: throw Unsupported("Conditionals") @@ -605,22 +614,6 @@ extension Compiler.ByteCodeGen { case let .convertedRegexLiteral(n, _): try emitNode(n) - case let .groupTransform(kind, child, t, referenceID): - guard let cap = try emitGroup(kind, child, referenceID) else { - assertionFailure(""" - What does it mean to not have a capture to transform? - """) - return - } - - // FIXME: Is this how we want to do it? - let transform = builder.makeTransformFunction { - input, range in - t(input[range]) - } - - builder.buildTransformCapture(cap, transform) - case .absentFunction: throw Unsupported("absent function") case .consumer: @@ -629,6 +622,10 @@ extension Compiler.ByteCodeGen { case let .matcher(_, f): emitMatcher(f) + case .transform: + throw Unreachable( + "Transforms only directly inside captures") + case .characterPredicate: throw Unsupported("character predicates") diff --git a/Sources/_StringProcessing/Capture.swift b/Sources/_StringProcessing/Capture.swift index 5b43da870..55e74684c 100644 --- a/Sources/_StringProcessing/Capture.swift +++ b/Sources/_StringProcessing/Capture.swift @@ -33,7 +33,7 @@ struct StoredCapture { } // TODO: Where should this live? Inside TypeConstruction? -func constructExistentialMatchComponent( +func constructExistentialOutputComponent( from input: Substring, in range: Range?, value: Any?, @@ -62,10 +62,10 @@ func constructExistentialMatchComponent( } extension StructuredCapture { - func existentialMatchComponent( + func existentialOutputComponent( from input: Substring ) -> Any { - constructExistentialMatchComponent( + constructExistentialOutputComponent( from: input, in: storedCapture?.range, value: storedCapture?.value, @@ -81,13 +81,13 @@ extension StructuredCapture { extension Sequence where Element == StructuredCapture { // FIXME: This is a stop gap where we still slice the input // and traffic through existentials - func existentialMatch( + func existentialOutput( from input: Substring ) -> Any { var caps = Array() caps.append(input) caps.append(contentsOf: self.map { - $0.existentialMatchComponent(from: input) + $0.existentialOutputComponent(from: input) }) return TypeConstruction.tuple(of: caps) } diff --git a/Sources/_StringProcessing/CharacterClass.swift b/Sources/_StringProcessing/CharacterClass.swift index 124669a43..d72ecf06c 100644 --- a/Sources/_StringProcessing/CharacterClass.swift +++ b/Sources/_StringProcessing/CharacterClass.swift @@ -178,7 +178,7 @@ public struct CharacterClass: Hashable { } } -extension RegexProtocol where Self == CharacterClass { +extension RegexComponent where Self == CharacterClass { public static var any: CharacterClass { .init(cc: .any, matchLevel: .graphemeCluster) } diff --git a/Sources/_StringProcessing/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index 47012a5c3..8bddb3a87 100644 --- a/Sources/_StringProcessing/ConsumerInterface.swift +++ b/Sources/_StringProcessing/ConsumerInterface.swift @@ -36,14 +36,17 @@ extension DSLTree.Node { case let .convertedRegexLiteral(n, _): return try n.generateConsumer(opts) - case .alternation, .conditional, .concatenation, .group, + case .orderedChoice, .conditional, .concatenation, + .capture, .nonCapturingGroup, .quantification, .trivia, .empty, - .groupTransform, .absentFunction: return nil + .absentFunction: return nil case .consumer: 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/Executor.swift b/Sources/_StringProcessing/Executor.swift index c044cbf24..15c1fe434 100644 --- a/Sources/_StringProcessing/Executor.swift +++ b/Sources/_StringProcessing/Executor.swift @@ -19,11 +19,11 @@ struct Executor { self.engine = Engine(program, enableTracing: enablesTracing) } - func match( + func match( _ input: String, in inputRange: Range, _ mode: MatchMode - ) throws -> RegexMatch? { + ) throws -> Regex.Match? { var cpu = engine.makeProcessor( input: input, bounds: inputRange, matchMode: mode) @@ -43,8 +43,8 @@ struct Executor { // FIXME: This is a workaround for not tracking (or // specially compiling) whole-match values. let value: Any? - if Match.self != Substring.self, - Match.self != (Substring, DynamicCaptures).self, + if Output.self != Substring.self, + Output.self != AnyRegexOutput.self, caps.isEmpty { value = cpu.registers.values.first @@ -53,7 +53,7 @@ struct Executor { value = nil } - return RegexMatch( + return .init( input: input, range: range, rawCaptures: caps, @@ -65,7 +65,7 @@ struct Executor { _ input: String, in inputRange: Range, _ mode: MatchMode - ) throws -> RegexMatch<(Substring, DynamicCaptures)>? { + ) throws -> Regex.Match? { try match(input, in: inputRange, mode) } } diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index b9c5943d4..f30d8d54b 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -73,7 +73,7 @@ extension PrettyPrinter { switch node { - case let .alternation(a): + case let .orderedChoice(a): printBlock("Alternation") { printer in a.forEach { printer.printAsPattern(convertedFromAST: $0) @@ -87,10 +87,18 @@ extension PrettyPrinter { } } - case let .group(kind, child, referenceID): + case let .nonCapturingGroup(kind, child): let kind = kind._patternBase - let refIDString = referenceID.map { ", referenceID: \($0)" } ?? "" - printBlock("Group(\(kind)\(refIDString)") { printer in + printBlock("Group(\(kind))") { printer in + printer.printAsPattern(convertedFromAST: child) + } + + case let .capture(name, _, child): + var cap = "capture" + if let n = name { + cap += "(\(n))" + } + printBlock(cap) { printer in printer.printAsPattern(convertedFromAST: child) } @@ -152,8 +160,8 @@ extension PrettyPrinter { case let .customCharacterClass(ccc): printAsPattern(ccc) - case .groupTransform: - print("/* TODO: group transforms */") + case .transform: + print("/* TODO: transforms */") case .consumer: print("/* TODO: consumers */") case .matcher: diff --git a/Sources/_StringProcessing/RegexDSL/ASTConversion.swift b/Sources/_StringProcessing/RegexDSL/ASTConversion.swift index 3ec12b85c..72dd11cdf 100644 --- a/Sources/_StringProcessing/RegexDSL/ASTConversion.swift +++ b/Sources/_StringProcessing/RegexDSL/ASTConversion.swift @@ -44,11 +44,11 @@ extension AST.Node { } // Convert the top-level node without wrapping - func convert() -> DSLTree.Node { + func convert() throws -> DSLTree.Node { switch self { case let .alternation(v): let children = v.children.map(\.dslTreeNode) - return .alternation(children) + return .orderedChoice(children) case let .concatenation(v): // Coalesce adjacent children who can produce a @@ -103,7 +103,16 @@ extension AST.Node { case let .group(v): let child = v.child.dslTreeNode - return .group(v.kind.value, child) + switch v.kind.value { + case .capture: + return .capture(child) + case .namedCapture(let name): + return .capture(name: name.value, child) + case .balancedCapture: + throw Unsupported("TODO: balanced captures") + default: + return .nonCapturingGroup(v.kind.value, child) + } case let .conditional(v): let trueBranch = v.trueBranch.dslTreeNode @@ -137,7 +146,8 @@ extension AST.Node { } } - let converted = convert() + // FIXME: make total function again + let converted = try! convert() return wrap(converted) } } diff --git a/Sources/_StringProcessing/RegexDSL/Anchor.swift b/Sources/_StringProcessing/RegexDSL/Anchor.swift index 1db481ee0..57d8f2ffa 100644 --- a/Sources/_StringProcessing/RegexDSL/Anchor.swift +++ b/Sources/_StringProcessing/RegexDSL/Anchor.swift @@ -27,7 +27,7 @@ public struct Anchor { var isInverted: Bool = false } -extension Anchor: RegexProtocol { +extension Anchor: RegexComponent { var astAssertion: AST.Atom.AssertionKind { if !isInverted { switch kind { @@ -106,16 +106,16 @@ extension Anchor { } } -public func lookahead( +public func lookahead( negative: Bool = false, - @RegexBuilder _ content: () -> R -) -> Regex { - Regex(node: .group(negative ? .negativeLookahead : .lookahead, content().regex.root)) + @RegexComponentBuilder _ content: () -> R +) -> Regex { + Regex(node: .nonCapturingGroup(negative ? .negativeLookahead : .lookahead, content().regex.root)) } -public func lookahead( +public func lookahead( _ component: R, negative: Bool = false -) -> Regex { - Regex(node: .group(negative ? .negativeLookahead : .lookahead, component.regex.root)) +) -> Regex { + Regex(node: .nonCapturingGroup(negative ? .negativeLookahead : .lookahead, component.regex.root)) } diff --git a/Sources/_StringProcessing/RegexDSL/AnyRegexOutput.swift b/Sources/_StringProcessing/RegexDSL/AnyRegexOutput.swift new file mode 100644 index 000000000..b1d9bfafa --- /dev/null +++ b/Sources/_StringProcessing/RegexDSL/AnyRegexOutput.swift @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +import _MatchingEngine + +extension Regex where Output == AnyRegexOutput { + public init(_ pattern: String) throws { + self.init(ast: try parse(pattern, .traditional)) + } +} + +extension Regex.Match where Output == AnyRegexOutput { + // Ensures `.0` always refers to the whole match. + public subscript( + dynamicMember keyPath: KeyPath<(Substring, _doNotUse: ()), Substring> + ) -> Substring { + input[range] + } +} + +public struct AnyRegexOutput { + let input: String + fileprivate let _elements: [ElementRepresentation] + + /// The underlying representation of the element of a type-erased regex + /// output. + fileprivate struct ElementRepresentation { + /// The depth of `Optioals`s wrapping the underlying value. For example, + /// `Substring` has optional depth `0`, and `Int??` has optional depth `2`. + let optionalDepth: Int + /// The bounds of the output element. + let bounds: Range? + } +} + +extension AnyRegexOutput { + /// Creates a type-erased regex output from an existing output. + /// + /// Use this initializer to fit a regex with strongly typed captures into the + /// use site of a dynamic regex, i.e. one that was created from a string. + public init(_ match: Regex.Match) { + // Note: We use type equality instead of `match.output as? ...` to prevent + // unexpected optional flattening. + if Output.self == AnyRegexOutput.self { + self = match.output as! AnyRegexOutput + return + } + fatalError("FIXME: Not implemented") + // self.init(input: match.input, _elements: ) + } + + /// Returns a typed output by converting the underlying value to the specified + /// type. + /// - Parameter type: The expected output type. + /// - Returns: The output, if the underlying value can be converted to the + /// output type, or nil otherwise. + public func `as`(_ type: Output.Type) -> Output? { + let elements = _elements.map { + StructuredCapture( + optionalCount: $0.optionalDepth, + storedCapture: .init(range: $0.bounds) + ).existentialOutputComponent(from: input[...]) + } + return TypeConstruction.tuple(of: elements) as? Output + } +} + +extension AnyRegexOutput { + internal init( + input: String, elements: C + ) where C.Element == StructuredCapture { + self.init(input: input, _elements: elements.map(ElementRepresentation.init)) + } +} + +extension AnyRegexOutput.ElementRepresentation { + init(_ element: StructuredCapture) { + self.init( + optionalDepth: element.optionalCount, + bounds: element.storedCapture.flatMap(\.range)) + } + + 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( + from: input, + in: bounds, + value: nil, + optionalCount: optionalDepth) + } +} + +extension AnyRegexOutput: RandomAccessCollection { + public struct Element { + fileprivate let representation: ElementRepresentation + let input: String + + public var range: Range? { + representation.bounds + } + + public var substring: Substring? { + range.map { input[$0] } + } + } + + public var startIndex: Int { + _elements.startIndex + } + + public var endIndex: Int { + _elements.endIndex + } + + public var count: Int { + _elements.count + } + + public func index(after i: Int) -> Int { + _elements.index(after: i) + } + + public func index(before i: Int) -> Int { + _elements.index(before: i) + } + + public subscript(position: Int) -> Element { + .init(representation: _elements[position], input: input) + } +} diff --git a/Sources/_StringProcessing/RegexDSL/Builder.swift b/Sources/_StringProcessing/RegexDSL/Builder.swift index f4b3516c3..78c122828 100644 --- a/Sources/_StringProcessing/RegexDSL/Builder.swift +++ b/Sources/_StringProcessing/RegexDSL/Builder.swift @@ -10,21 +10,24 @@ //===----------------------------------------------------------------------===// @resultBuilder -public enum RegexBuilder { - @_disfavoredOverload - public static func buildBlock(_ r0: R0) -> R0 { - r0 +public enum RegexComponentBuilder { + public static func buildBlock() -> Regex { + .init(node: .empty) } - public static func buildExpression(_ regex: R) -> R { + public static func buildPartialBlock(first: R ) -> R { + first + } + + public static func buildExpression(_ regex: R) -> R { regex } - public static func buildEither(first component: R) -> R { + public static func buildEither(first component: R) -> R { component } - public static func buildEither(second component: R) -> R { + public static func buildEither(second component: R) -> R { component } } diff --git a/Sources/_StringProcessing/RegexDSL/Core.swift b/Sources/_StringProcessing/RegexDSL/Core.swift index fe6f60bd9..236888c77 100644 --- a/Sources/_StringProcessing/RegexDSL/Core.swift +++ b/Sources/_StringProcessing/RegexDSL/Core.swift @@ -13,13 +13,13 @@ import _MatchingEngine /// A type that represents a regular expression. -public protocol RegexProtocol { - associatedtype Match - var regex: Regex { get } +public protocol RegexComponent { + associatedtype Output + var regex: Regex { get } } /// A regular expression. -public struct Regex: RegexProtocol { +public struct Regex: RegexComponent { /// A program representation that caches any lowered representation for /// execution. internal class Program { @@ -78,39 +78,39 @@ public struct Regex: RegexProtocol { self.init(ast: try! parseWithDelimiters(pattern)) } - public init( + public init( _ content: Content - ) where Content.Match == Match { + ) where Content.Output == Output { self = content.regex } - public init( - @RegexBuilder _ content: () -> Content - ) where Content.Match == Match { + public init( + @RegexComponentBuilder _ content: () -> Content + ) where Content.Output == Output { self.init(content()) } - public var regex: Regex { + public var regex: Regex { self } } -public struct MockRegexLiteral: RegexProtocol { +public struct MockRegexLiteral: RegexComponent { public typealias MatchValue = Substring - public let regex: Regex + public let regex: Regex public init( _ string: String, _ syntax: SyntaxOptions = .traditional, - matching: Match.Type = Match.self + matching: Output.Type = Output.self ) throws { regex = Regex(ast: try parse(string, syntax)) } } -public func r( - _ s: String, matching matchType: Match.Type = Match.self -) -> MockRegexLiteral { +public func r( + _ s: String, matching matchType: Output.Type = Output.self +) -> MockRegexLiteral { try! MockRegexLiteral(s, matching: matchType) } diff --git a/Sources/_StringProcessing/RegexDSL/DSL.swift b/Sources/_StringProcessing/RegexDSL/DSL.swift index a21dce82d..4c3c382cc 100644 --- a/Sources/_StringProcessing/RegexDSL/DSL.swift +++ b/Sources/_StringProcessing/RegexDSL/DSL.swift @@ -11,44 +11,56 @@ import _MatchingEngine +// A convenience protocol for builtin regex components that are initialized with +// a `DSLTree` node. +internal protocol _BuiltinRegexComponent: RegexComponent { + init(_ regex: Regex) +} + +extension _BuiltinRegexComponent { + init(node: DSLTree.Node) { + self.init(Regex(node: node)) + } +} + // MARK: - Primitives -extension String: RegexProtocol { - public typealias Match = Substring +extension String: RegexComponent { + public typealias Output = Substring - public var regex: Regex { + public var regex: Regex { .init(node: .quotedLiteral(self)) } } -extension Substring: RegexProtocol { - public typealias Match = Substring +extension Substring: RegexComponent { + public typealias Output = Substring - public var regex: Regex { + public var regex: Regex { .init(node: .quotedLiteral(String(self))) } } -extension Character: RegexProtocol { - public typealias Match = Substring +extension Character: RegexComponent { + public typealias Output = Substring - public var regex: Regex { + public var regex: Regex { .init(node: .atom(.char(self))) } } -extension UnicodeScalar: RegexProtocol { - public typealias Match = Substring +extension UnicodeScalar: RegexComponent { + public typealias Output = Substring - public var regex: Regex { + public var regex: Regex { .init(node: .atom(.scalar(self))) } } -extension CharacterClass: RegexProtocol { - public typealias Match = Substring +extension CharacterClass: RegexComponent { + public typealias Output = Substring - public var regex: Regex { + public var regex: Regex { guard let ast = self.makeAST() else { fatalError("FIXME: extended AST?") } @@ -63,11 +75,11 @@ extension CharacterClass: RegexProtocol { // Note: Concatenation overloads are currently gyb'd. // TODO: Variadic generics -// struct Concatenation +// struct Concatenation // where R0.Match == (W0, C0...), R1.Match == (W1, C1...) // { // typealias Match = (Substring, C0..., C1...) -// let regex: Regex +// let regex: Regex // init(_ first: R0, _ second: R1) { // regex = .init(concat(r0, r1)) // } @@ -115,37 +127,49 @@ extension QuantificationBehavior { } } -// TODO: Variadic generics -// struct _OneOrMore -// where R.Match == (W, C...) -// { -// typealias Match = (Substring, [(C...)]) -// let regex: Regex -// init(_ component: Component) { -// regex = .init(oneOrMore(r0)) -// } -// } -// -// struct _OneOrMoreNonCapturing { -// typealias Match = Substring -// let regex: Regex -// init(_ component: Component) { -// regex = .init(oneOrMore(r0)) -// } -// } -// -// func oneOrMore( -// _ component: Component -// ) -> R { -// _OneOrMore(component) -// } -// -// @_disfavoredOverload -// func oneOrMore( -// _ component: Component -// ) -> R { -// _OneOrMoreNonCapturing(component) -// } +public struct OneOrMore: _BuiltinRegexComponent { + public var regex: Regex + + internal init(_ regex: Regex) { + self.regex = regex + } + + // Note: Public initializers and operators are currently gyb'd. See + // Variadics.swift. +} + +public struct ZeroOrMore: _BuiltinRegexComponent { + public var regex: Regex + + internal init(_ regex: Regex) { + self.regex = regex + } + + // Note: Public initializers and operators are currently gyb'd. See + // Variadics.swift. +} + +public struct Optionally: _BuiltinRegexComponent { + public var regex: Regex + + internal init(_ regex: Regex) { + self.regex = regex + } + + // Note: Public initializers and operators are currently gyb'd. See + // Variadics.swift. +} + +public struct Repeat: _BuiltinRegexComponent { + public var regex: Regex + + internal init(_ regex: Regex) { + self.regex = regex + } + + // Note: Public initializers and operators are currently gyb'd. See + // Variadics.swift. +} postfix operator .? postfix operator .* @@ -157,9 +181,9 @@ postfix operator .+ // @resultBuilder // struct AlternationBuilder { // @_disfavoredOverload -// func buildBlock(_ regex: R) -> R +// func buildBlock(_ regex: R) -> R // func buildBlock< -// R: RegexProtocol, W0, C0... +// R: RegexComponent, W0, C0... // >( // _ regex: R // ) -> R where R.Match == (W, C...) @@ -168,27 +192,57 @@ postfix operator .+ @resultBuilder public struct AlternationBuilder { @_disfavoredOverload - public static func buildBlock(_ regex: R) -> R { - regex + public static func buildPartialBlock( + first component: R + ) -> ChoiceOf { + .init(component.regex) } - public static func buildExpression(_ regex: R) -> R { + public static func buildExpression(_ regex: R) -> R { regex } - public static func buildEither(first component: R) -> R { + public static func buildEither(first component: R) -> R { component } - public static func buildEither(second component: R) -> R { + public static func buildEither(second component: R) -> R { component } } -public func choiceOf( - @AlternationBuilder builder: () -> R -) -> R { - builder() +public struct ChoiceOf: _BuiltinRegexComponent { + public var regex: Regex + + internal init(_ regex: Regex) { + self.regex = regex + } + + public init(@AlternationBuilder _ builder: () -> Self) { + self = builder() + } +} + +// MARK: - Capture + +public struct Capture: _BuiltinRegexComponent { + public var regex: Regex + + internal init(_ regex: Regex) { + self.regex = regex + } + + // Note: Public initializers are currently gyb'd. See Variadics.swift. +} + +public struct TryCapture: _BuiltinRegexComponent { + public var regex: Regex + + internal init(_ regex: Regex) { + self.regex = regex + } + + // Note: Public initializers are currently gyb'd. See Variadics.swift. } // MARK: - Backreference @@ -203,7 +257,7 @@ struct ReferenceID: Hashable, Equatable { } } -public struct Reference: RegexProtocol { +public struct Reference: RegexComponent { let id = ReferenceID() public init(_ captureType: Capture.Type = Capture.self) {} diff --git a/Sources/_StringProcessing/RegexDSL/DSLConsumers.swift b/Sources/_StringProcessing/RegexDSL/DSLConsumers.swift index 79b165655..8d64f8355 100644 --- a/Sources/_StringProcessing/RegexDSL/DSLConsumers.swift +++ b/Sources/_StringProcessing/RegexDSL/DSLConsumers.swift @@ -9,17 +9,17 @@ // //===----------------------------------------------------------------------===// -public protocol CustomRegexComponent: RegexProtocol { +public protocol CustomRegexComponent: RegexComponent { func match( _ input: String, startingAt index: String.Index, in bounds: Range - ) -> (upperBound: String.Index, match: Match)? + ) -> (upperBound: String.Index, output: Output)? } extension CustomRegexComponent { - public var regex: Regex { - Regex(node: .matcher(.init(Match.self), { input, index, bounds in + public var regex: Regex { + Regex(node: .matcher(.init(Output.self), { input, index, bounds in match(input, startingAt: index, in: bounds) })) } diff --git a/Sources/_StringProcessing/RegexDSL/DSLTree.swift b/Sources/_StringProcessing/RegexDSL/DSLTree.swift index 43f8aa62f..25a5943c0 100644 --- a/Sources/_StringProcessing/RegexDSL/DSLTree.swift +++ b/Sources/_StringProcessing/RegexDSL/DSLTree.swift @@ -23,18 +23,32 @@ struct DSLTree { extension DSLTree { indirect enum Node: _TreeNode { - /// ... | ... | ... - case alternation([Node]) + /// Try to match each node in order + /// + /// ... | ... | ... + case orderedChoice([Node]) - /// ... ... + /// Match each node in sequence + /// + /// ... ... case concatenation([Node]) - /// (...) - case group(AST.Group.Kind, Node, ReferenceID? = nil) + /// Capture the result of a subpattern + /// + /// (...), (?...) + case capture( + name: String? = nil, reference: ReferenceID? = nil, Node) + + /// Match a (non-capturing) subpattern / group + case nonCapturingGroup(AST.Group.Kind, Node) - /// (?(cond) true-branch | false-branch) + // TODO: Consider splitting off grouped conditions, or have + // our own kind + + /// Match a choice of two nodes based on a condition + /// + /// (?(cond) true-branch | false-branch) /// - /// TODO: Consider splitting off grouped conditions, or have our own kind case conditional( AST.Conditional.Condition.Kind, Node, Node) @@ -74,15 +88,8 @@ extension DSLTree { // MARK: - Extensibility points - /// A capturing group (TODO: is it?) with a transformation function - /// - /// TODO: Consider as a validator or constructor nested in a - /// group, or split capturing off of group. - case groupTransform( - AST.Group.Kind, - Node, - CaptureTransform, - ReferenceID? = nil) + /// Transform a range into a value, most often used inside captures + case transform(CaptureTransform, Node) case consumer(_ConsumerInterface) @@ -157,16 +164,17 @@ extension DSLTree.Node { var children: [DSLTree.Node]? { switch self { - case let .alternation(v): return v + case let .orderedChoice(v): return v case let .concatenation(v): return v case let .convertedRegexLiteral(n, _): // Treat this transparently return n.children - case let .group(_, n, _): return [n] - case let .groupTransform(_, n, _, _): return [n] - case let .quantification(_, _, 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] @@ -226,18 +234,17 @@ extension DSLTree { extension DSLTree.Node { var hasCapture: Bool { switch self { - case let .group(k, _, _) where k.isCapturing, - let .groupTransform(k, _, _, _) where k.isCapturing: + case .capture: return true + case let .regexLiteral(re): + return re.hasCapture case let .convertedRegexLiteral(n, re): assert(n.hasCapture == re.hasCapture) return n.hasCapture - case let .regexLiteral(re): - return re.hasCapture + default: - break + return self.children?.any(\.hasCapture) ?? false } - return self.children?.any(\.hasCapture) ?? false } } @@ -253,22 +260,22 @@ extension DSLTree.Node { _ constructor: inout CaptureStructure.Constructor ) -> CaptureStructure { switch self { - case let .alternation(children): + case let .orderedChoice(children): return constructor.alternating(children) case let .concatenation(children): return constructor.concatenating(children) - case let .group(kind, child, _): - if let type = child.matcherCaptureType { - return constructor.grouping( - child, as: kind, withType: type) + case let .capture(name, _, child): + if let type = child.valueCaptureType { + return constructor.capturing( + name: name, child, withType: type) } - return constructor.grouping(child, as: kind) + return constructor.capturing(name: name, child) - case let .groupTransform(kind, child, transform, _): - return constructor.grouping( - child, as: kind, withTransform: transform) + case let .nonCapturingGroup(kind, child): + assert(!kind.isCapturing) + return constructor.grouping(child, as: kind) case let .conditional(cond, trueBranch, falseBranch): return constructor.condition( @@ -294,17 +301,22 @@ extension DSLTree.Node { case .matcher: return .empty + case .transform(_, let child): + return child._captureStructure(&constructor) + case .customCharacterClass, .atom, .trivia, .empty, .quotedLiteral, .consumer, .characterPredicate: return .empty } } - // TODO: Unify with group transform - var matcherCaptureType: AnyType? { + /// For typed capture-producing nodes, the type produced. + var valueCaptureType: AnyType? { switch self { case let .matcher(t, _): return t + case let .transform(t, _): + return AnyType(t.resultType) default: return nil } } @@ -319,10 +331,10 @@ extension DSLTree.Node { } func appendingAlternationCase(_ newNode: DSLTree.Node) -> DSLTree.Node { - if case .alternation(let components) = self { - return .alternation(components + [newNode]) + if case .orderedChoice(let components) = self { + return .orderedChoice(components + [newNode]) } - return .alternation([self, newNode]) + return .orderedChoice([self, newNode]) } } diff --git a/Sources/_StringProcessing/RegexDSL/DynamicCaptures.swift b/Sources/_StringProcessing/RegexDSL/DynamicCaptures.swift deleted file mode 100644 index 24c182564..000000000 --- a/Sources/_StringProcessing/RegexDSL/DynamicCaptures.swift +++ /dev/null @@ -1,84 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// -//===----------------------------------------------------------------------===// - -import _MatchingEngine - -extension Regex where Match == (Substring, DynamicCaptures) { - public init(_ pattern: String) throws { - self.init(ast: try parse(pattern, .traditional)) - } -} - -// FIXME: Separate storage representation from types vending -// API. -public typealias DynamicCaptures = Array - -// FIXME: Make this internal when we have API types or otherwise -// disentagle storage from API. In the meantime, this will have -// the storage name _and_ provide the API. -public struct StoredDynamicCapture: Hashable { - var optionalCount = 0 - - // TODO: replace with a range - var slice: Substring? - - init(_ slice: Substring?, optionalCount: Int) { - self.slice = slice - self.optionalCount = optionalCount - } -} - -extension StoredDynamicCapture { - // TODO: How should we expose optional nesting? - - public var range: Range? { - guard let s = slice else { - return nil - } - return s.startIndex.. { - let input: String - public let range: Range - let rawCaptures: [StructuredCapture] - let referencedCaptureOffsets: [ReferenceID: Int] +extension Regex { + @dynamicMemberLookup + public struct Match { + let input: String + public let range: Range + let rawCaptures: [StructuredCapture] + let referencedCaptureOffsets: [ReferenceID: Int] - let value: Any? + let value: Any? + } +} - public var match: Match { - if Match.self == (Substring, DynamicCaptures).self { - // FIXME(rdar://89449323): Compiler assertion - let input = input - let dynCaps = rawCaptures.map { StoredDynamicCapture($0, in: input) } - return (input[range], dynCaps) as! Match - } else if Match.self == Substring.self { +extension Regex.Match { + public var output: Output { + if Output.self == AnyRegexOutput.self { + let wholeMatchAsCapture = StructuredCapture( + optionalCount: 0, + storedCapture: StoredCapture(range: range, value: nil)) + let output = AnyRegexOutput( + input: input, + elements: [wholeMatchAsCapture] + rawCaptures) + return output as! Output + } else if Output.self == Substring.self { // FIXME: Plumb whole match (`.0`) through the matching engine. - return input[range] as! Match + return input[range] as! Output } else if rawCaptures.isEmpty, value != nil { // 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! Match + return value! as! Output } else { guard value == nil else { fatalError("FIXME: what would this mean?") } - let typeErasedMatch = rawCaptures.existentialMatch(from: input[range]) - return typeErasedMatch as! Match + let typeErasedMatch = rawCaptures.existentialOutput(from: input[range]) + return typeErasedMatch as! Output } } - public subscript(dynamicMember keyPath: KeyPath) -> T { - match[keyPath: keyPath] + public subscript(dynamicMember keyPath: KeyPath) -> T { + output[keyPath: keyPath] } // Allows `.0` when `Match` is not a tuple. @_disfavoredOverload public subscript( - dynamicMember keyPath: KeyPath<(Match, _doNotUse: ()), Match> - ) -> Match { - match + dynamicMember keyPath: KeyPath<(Output, _doNotUse: ()), Output> + ) -> Output { + output } public subscript(_ reference: Reference) -> Capture { @@ -58,17 +65,17 @@ public struct RegexMatch { preconditionFailure( "Reference did not capture any match in the regex") } - return rawCaptures[offset].existentialMatchComponent(from: input[...]) + return rawCaptures[offset].existentialOutputComponent(from: input[...]) as! Capture } } -extension RegexProtocol { - public func match(in input: String) -> RegexMatch? { +extension RegexComponent { + public func match(in input: String) -> Regex.Match? { _match( input, in: input.startIndex.. RegexMatch? { + public func match(in input: Substring) -> Regex.Match? { _match( input.base, in: input.startIndex.., mode: MatchMode = .wholeString - ) -> RegexMatch? { + ) -> Regex.Match? { let executor = Executor(program: regex.program.loweredProgram) do { return try executor.match(input, in: inputRange, mode) @@ -88,24 +95,24 @@ extension RegexProtocol { } extension String { - public func match(_ regex: R) -> RegexMatch? { + public func match(_ regex: R) -> Regex.Match? { regex.match(in: self) } - public func match( - @RegexBuilder _ content: () -> R - ) -> RegexMatch? { + public func match( + @RegexComponentBuilder _ content: () -> R + ) -> Regex.Match? { match(content()) } } extension Substring { - public func match(_ regex: R) -> RegexMatch? { + public func match(_ regex: R) -> Regex.Match? { regex.match(in: self) } - public func match( - @RegexBuilder _ content: () -> R - ) -> RegexMatch? { + public func match( + @RegexComponentBuilder _ content: () -> R + ) -> Regex.Match? { match(content()) } } diff --git a/Sources/_StringProcessing/RegexDSL/Options.swift b/Sources/_StringProcessing/RegexDSL/Options.swift index da6df0a8e..7876ae35c 100644 --- a/Sources/_StringProcessing/RegexDSL/Options.swift +++ b/Sources/_StringProcessing/RegexDSL/Options.swift @@ -11,8 +11,8 @@ import _MatchingEngine -extension RegexProtocol { - public func caseSensitive(_ isCaseSensitive: Bool) -> Regex { +extension RegexComponent { + public func caseSensitive(_ isCaseSensitive: Bool) -> Regex { // The API is "case sensitive = true or false", so as to avoid the // double negatives inherent in setting "case insensitive" to a Boolean // value. The internal version of this option, on the other hand, is @@ -20,7 +20,9 @@ extension RegexProtocol { let sequence = isCaseSensitive ? AST.MatchingOptionSequence(removing: [.init(.caseInsensitive, location: .fake)]) : AST.MatchingOptionSequence(adding: [.init(.caseInsensitive, location: .fake)]) - return Regex(node: .group(.changeMatchingOptions(sequence, isIsolated: false), regex.root)) + return Regex(node: .nonCapturingGroup( + .changeMatchingOptions(sequence, isIsolated: false), + regex.root)) } } diff --git a/Sources/_StringProcessing/RegexDSL/Variadics.swift b/Sources/_StringProcessing/RegexDSL/Variadics.swift index 3ca1261f1..c81f8b555 100644 --- a/Sources/_StringProcessing/RegexDSL/Variadics.swift +++ b/Sources/_StringProcessing/RegexDSL/Variadics.swift @@ -13,3844 +13,4617 @@ import _MatchingEngine -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0)> where R0.Match == W0, R1.Match == (W1, C0) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0)> where R0.Output == W0, R1.Output == (W1, C0) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1)> where R0.Match == W0, R1.Match == (W1, C0, C1) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1)> where R0.Output == W0, R1.Output == (W1, C0, C1) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2)> where R0.Match == W0, R1.Match == (W1, C0, C1, C2) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Match == W0, R1.Match == (W1, C0, C1, C2, C3) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Match == W0, R1.Match == (W1, C0, C1, C2, C3, C4) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Match == W0, R1.Match == (W1, C0, C1, C2, C3, C4, C5) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4, C5) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Match == W0, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Match == W0, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Match == W0, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Match == W0, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == W0, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1)> where R0.Match == (W0, C0), R1.Match == (W1, C1) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1)> where R0.Output == (W0, C0), R1.Output == (W1, C1) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2)> where R0.Match == (W0, C0), R1.Match == (W1, C1, C2) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2)> where R0.Match == (W0, C0, C1), R1.Match == (W1, C2) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7, C8) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7, C8) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7, C8) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7, C8, C9) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7, C8) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7, C8) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7, C8, C9) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7, C8, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Match == (W1, C8) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (W1, C8) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Match == (W1, C8, C9) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (W1, C8, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.Match == (W1, C9) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.Output == (W1, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex where R0.Match == W0 { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex where R0.Output == W0 { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0)> where R0.Match == (W0, C0) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0)> where R0.Output == (W0, C0) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1)> where R0.Match == (W0, C0, C1) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1)> where R0.Output == (W0, C0, C1) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2)> where R0.Match == (W0, C0, C1, C2) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2)> where R0.Output == (W0, C0, C1, C2) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Match == (W0, C0, C1, C2, C3) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.Output == (W0, C0, C1, C2, C3) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Match == (W0, C0, C1, C2, C3, C4) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.Output == (W0, C0, C1, C2, C3, C4) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -extension RegexBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appending(next.regex.root)) +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appending(next.regex.root)) + } +} +extension RegexComponentBuilder { + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appending(next.regex.root)) } } -@_disfavoredOverload -public func optionally( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) +extension Optionally { + @_disfavoredOverload + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == Substring { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -@_disfavoredOverload -public func optionally( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) +extension Optionally { + @_disfavoredOverload + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } @_disfavoredOverload -public postfix func .?( +public postfix func .?( _ component: Component -) -> Regex { +) -> Optionally { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -extension RegexBuilder { - public static func buildLimitedAvailability( +extension RegexComponentBuilder { + public static func buildLimitedAvailability( _ component: Component ) -> Regex { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } -@_disfavoredOverload -public func zeroOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) +extension ZeroOrMore { + @_disfavoredOverload + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == Substring { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } } -@_disfavoredOverload -public func zeroOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) +extension ZeroOrMore { + @_disfavoredOverload + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } } @_disfavoredOverload -public postfix func .*( +public postfix func .*( _ component: Component -) -> Regex { +) -> ZeroOrMore { .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) } -@_disfavoredOverload -public func oneOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex { - .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) +extension OneOrMore { + @_disfavoredOverload + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == Substring { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } } -@_disfavoredOverload -public func oneOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex { - .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) +extension OneOrMore { + @_disfavoredOverload + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } } @_disfavoredOverload -public postfix func .+( +public postfix func .+( _ component: Component -) -> Regex { +) -> OneOrMore { .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) } -@_disfavoredOverload -public func repeating( - _ component: Component, - count: Int -) -> Regex { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) -} +extension Repeat { + @_disfavoredOverload + public init( + _ component: Component, + count: Int + ) where Output == Substring { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } -@_disfavoredOverload -public func repeating( - count: Int, - @RegexBuilder _ component: () -> Component -) -> Regex { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) -} + @_disfavoredOverload + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } -@_disfavoredOverload -public func repeating( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex where R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == Substring, R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex where R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == Substring, R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?)> where Component.Match == (W, C0) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) +extension Optionally { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?), Component.Output == (W, C0) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -public func optionally( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?)> where Component.Match == (W, C0) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) +extension Optionally { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?), Component.Output == (W, C0) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } -public postfix func .?( +public postfix func .?( _ component: Component -) -> Regex<(Substring, C0?)> where Component.Match == (W, C0) { +) -> Optionally<(Substring, C0?)> where Component.Output == (W, C0) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -extension RegexBuilder { - public static func buildLimitedAvailability( +extension RegexComponentBuilder { + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?)> where Component.Match == (W, C0) { + ) -> Regex<(Substring, C0?)> where Component.Output == (W, C0) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } -public func zeroOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?)> where Component.Match == (W, C0) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) +extension ZeroOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?), Component.Output == (W, C0) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } } -public func zeroOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?)> where Component.Match == (W, C0) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) +extension ZeroOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?), Component.Output == (W, C0) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .*( +public postfix func .*( _ component: Component -) -> Regex<(Substring, C0?)> where Component.Match == (W, C0) { +) -> ZeroOrMore<(Substring, C0?)> where Component.Output == (W, C0) { .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) } -public func oneOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0)> where Component.Match == (W, C0) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) +extension OneOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0), Component.Output == (W, C0) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } } -public func oneOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0)> where Component.Match == (W, C0) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) +extension OneOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0), Component.Output == (W, C0) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .+( +public postfix func .+( _ component: Component -) -> Regex<(Substring, C0)> where Component.Match == (W, C0) { +) -> OneOrMore<(Substring, C0)> where Component.Output == (W, C0) { .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) } -public func repeating( - _ component: Component, - count: Int -) -> Regex<(Substring, C0?)> where Component.Match == (W, C0) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) -} +extension Repeat { + public init( + _ component: Component, + count: Int + ) where Output == (Substring, C0?), Component.Output == (W, C0) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } -public func repeating( - count: Int, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?)> where Component.Match == (W, C0) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) -} + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?), Component.Output == (W, C0) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } -public func repeating( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?)> where Component.Match == (W, C0), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?), Component.Output == (W, C0), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?)> where Component.Match == (W, C0), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?), Component.Output == (W, C0), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) +extension Optionally { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -public func optionally( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) +extension Optionally { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } -public postfix func .?( +public postfix func .?( _ component: Component -) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1) { +) -> Optionally<(Substring, C0?, C1?)> where Component.Output == (W, C0, C1) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -extension RegexBuilder { - public static func buildLimitedAvailability( +extension RegexComponentBuilder { + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1) { + ) -> Regex<(Substring, C0?, C1?)> where Component.Output == (W, C0, C1) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } -public func zeroOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) +extension ZeroOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } } -public func zeroOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) +extension ZeroOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .*( +public postfix func .*( _ component: Component -) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1) { +) -> ZeroOrMore<(Substring, C0?, C1?)> where Component.Output == (W, C0, C1) { .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) } -public func oneOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0, C1)> where Component.Match == (W, C0, C1) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) +extension OneOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } } -public func oneOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0, C1)> where Component.Match == (W, C0, C1) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) +extension OneOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .+( +public postfix func .+( _ component: Component -) -> Regex<(Substring, C0, C1)> where Component.Match == (W, C0, C1) { +) -> OneOrMore<(Substring, C0, C1)> where Component.Output == (W, C0, C1) { .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) } -public func repeating( - _ component: Component, - count: Int -) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) -} +extension Repeat { + public init( + _ component: Component, + count: Int + ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } -public func repeating( - count: Int, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) -} + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } -public func repeating( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?)> where Component.Match == (W, C0, C1), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) +extension Optionally { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -public func optionally( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) +extension Optionally { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } -public postfix func .?( +public postfix func .?( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2) { +) -> Optionally<(Substring, C0?, C1?, C2?)> where Component.Output == (W, C0, C1, C2) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -extension RegexBuilder { - public static func buildLimitedAvailability( +extension RegexComponentBuilder { + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2) { + ) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Output == (W, C0, C1, C2) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } -public func zeroOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) +extension ZeroOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } } -public func zeroOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) +extension ZeroOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .*( +public postfix func .*( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2) { +) -> ZeroOrMore<(Substring, C0?, C1?, C2?)> where Component.Output == (W, C0, C1, C2) { .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) } -public func oneOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0, C1, C2)> where Component.Match == (W, C0, C1, C2) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) +extension OneOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0, C1, C2), Component.Output == (W, C0, C1, C2) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } } -public func oneOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0, C1, C2)> where Component.Match == (W, C0, C1, C2) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) +extension OneOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0, C1, C2), Component.Output == (W, C0, C1, C2) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .+( +public postfix func .+( _ component: Component -) -> Regex<(Substring, C0, C1, C2)> where Component.Match == (W, C0, C1, C2) { +) -> OneOrMore<(Substring, C0, C1, C2)> where Component.Output == (W, C0, C1, C2) { .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) } -public func repeating( - _ component: Component, - count: Int -) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) -} +extension Repeat { + public init( + _ component: Component, + count: Int + ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } -public func repeating( - count: Int, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) -} + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } -public func repeating( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Match == (W, C0, C1, C2), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) +extension Optionally { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -public func optionally( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) +extension Optionally { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } -public postfix func .?( +public postfix func .?( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3) { +) -> Optionally<(Substring, C0?, C1?, C2?, C3?)> where Component.Output == (W, C0, C1, C2, C3) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -extension RegexBuilder { - public static func buildLimitedAvailability( +extension RegexComponentBuilder { + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Output == (W, C0, C1, C2, C3) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } -public func zeroOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) +extension ZeroOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } } -public func zeroOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) +extension ZeroOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .*( +public postfix func .*( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3) { +) -> ZeroOrMore<(Substring, C0?, C1?, C2?, C3?)> where Component.Output == (W, C0, C1, C2, C3) { .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) } -public func oneOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0, C1, C2, C3)> where Component.Match == (W, C0, C1, C2, C3) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) +extension OneOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (W, C0, C1, C2, C3) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } } -public func oneOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0, C1, C2, C3)> where Component.Match == (W, C0, C1, C2, C3) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) +extension OneOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (W, C0, C1, C2, C3) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .+( +public postfix func .+( _ component: Component -) -> Regex<(Substring, C0, C1, C2, C3)> where Component.Match == (W, C0, C1, C2, C3) { +) -> OneOrMore<(Substring, C0, C1, C2, C3)> where Component.Output == (W, C0, C1, C2, C3) { .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) } -public func repeating( - _ component: Component, - count: Int -) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) -} +extension Repeat { + public init( + _ component: Component, + count: Int + ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } -public func repeating( - count: Int, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) -} + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } -public func repeating( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Match == (W, C0, C1, C2, C3), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) +extension Optionally { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -public func optionally( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) +extension Optionally { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } -public postfix func .?( +public postfix func .?( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4) { +) -> Optionally<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Output == (W, C0, C1, C2, C3, C4) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -extension RegexBuilder { - public static func buildLimitedAvailability( +extension RegexComponentBuilder { + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Output == (W, C0, C1, C2, C3, C4) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } -public func zeroOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) +extension ZeroOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } } -public func zeroOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) +extension ZeroOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .*( +public postfix func .*( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4) { +) -> ZeroOrMore<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Output == (W, C0, C1, C2, C3, C4) { .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) } -public func oneOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0, C1, C2, C3, C4)> where Component.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) +extension OneOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } } -public func oneOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0, C1, C2, C3, C4)> where Component.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) +extension OneOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .+( +public postfix func .+( _ component: Component -) -> Regex<(Substring, C0, C1, C2, C3, C4)> where Component.Match == (W, C0, C1, C2, C3, C4) { +) -> OneOrMore<(Substring, C0, C1, C2, C3, C4)> where Component.Output == (W, C0, C1, C2, C3, C4) { .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) } -public func repeating( - _ component: Component, - count: Int -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) -} +extension Repeat { + public init( + _ component: Component, + count: Int + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } -public func repeating( - count: Int, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) -} + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } -public func repeating( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Match == (W, C0, C1, C2, C3, C4), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) +extension Optionally { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -public func optionally( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) +extension Optionally { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } -public postfix func .?( +public postfix func .?( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { +) -> Optionally<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -extension RegexBuilder { - public static func buildLimitedAvailability( +extension RegexComponentBuilder { + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } -public func zeroOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) +extension ZeroOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } } -public func zeroOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) +extension ZeroOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .*( +public postfix func .*( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { +) -> ZeroOrMore<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5) { .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) } -public func oneOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) +extension OneOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0, C1, C2, C3, C4, C5), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } } -public func oneOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) +extension OneOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0, C1, C2, C3, C4, C5), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .+( +public postfix func .+( _ component: Component -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { +) -> OneOrMore<(Substring, C0, C1, C2, C3, C4, C5)> where Component.Output == (W, C0, C1, C2, C3, C4, C5) { .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) } -public func repeating( - _ component: Component, - count: Int -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) -} +extension Repeat { + public init( + _ component: Component, + count: Int + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } -public func repeating( - count: Int, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) -} + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } -public func repeating( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) +extension Optionally { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -public func optionally( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) +extension Optionally { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } -public postfix func .?( +public postfix func .?( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { +) -> Optionally<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -extension RegexBuilder { - public static func buildLimitedAvailability( +extension RegexComponentBuilder { + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } -public func zeroOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) +extension ZeroOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } } -public func zeroOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) +extension ZeroOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .*( +public postfix func .*( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { +) -> ZeroOrMore<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) } -public func oneOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) +extension OneOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } } -public func oneOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) +extension OneOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .+( +public postfix func .+( _ component: Component -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { +) -> OneOrMore<(Substring, C0, C1, C2, C3, C4, C5, C6)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) } -public func repeating( - _ component: Component, - count: Int -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) -} +extension Repeat { + public init( + _ component: Component, + count: Int + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } -public func repeating( - count: Int, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) -} + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } -public func repeating( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) +extension Optionally { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -public func optionally( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) +extension Optionally { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } -public postfix func .?( +public postfix func .?( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { +) -> Optionally<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -extension RegexBuilder { - public static func buildLimitedAvailability( +extension RegexComponentBuilder { + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } -public func zeroOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) +extension ZeroOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } } -public func zeroOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) +extension ZeroOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .*( +public postfix func .*( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { +) -> ZeroOrMore<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) } -public func oneOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) +extension OneOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } } -public func oneOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) +extension OneOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .+( +public postfix func .+( _ component: Component -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { +) -> OneOrMore<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) } -public func repeating( - _ component: Component, - count: Int -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) -} +extension Repeat { + public init( + _ component: Component, + count: Int + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } -public func repeating( - count: Int, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) -} + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } -public func repeating( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) +extension Optionally { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -public func optionally( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) +extension Optionally { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } -public postfix func .?( +public postfix func .?( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { +) -> Optionally<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -extension RegexBuilder { - public static func buildLimitedAvailability( +extension RegexComponentBuilder { + public static func buildLimitedAvailability( _ component: Component - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } } -public func zeroOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) +extension ZeroOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } } -public func zeroOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) +extension ZeroOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .*( +public postfix func .*( _ component: Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { +) -> ZeroOrMore<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) } -public func oneOrMore( - _ component: Component, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) +extension OneOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } } -public func oneOrMore( - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) +extension OneOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } } -public postfix func .+( +public postfix func .+( _ component: Component -) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { +) -> OneOrMore<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) } -public func repeating( - _ component: Component, - count: Int -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) +extension Repeat { + public init( + _ component: Component, + count: Int + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } + + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } + + public init( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + } } -public func repeating( - count: Int, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - assert(count > 0, "Must specify a positive count") - // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) +extension Optionally { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + } } -public func repeating( - _ component: Component, - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component +) -> Optionally<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) } -public func repeating( - _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, - @RegexBuilder _ component: () -> Component -) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { - .init(node: .repeating(expression.relative(to: 0..( + _ component: Component + ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + } +} +extension ZeroOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + } +} + +extension ZeroOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + } +} + +public postfix func .*( + _ component: Component +) -> ZeroOrMore<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) +} + + +extension OneOrMore { + public init( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + } +} + +extension OneOrMore { + public init( + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + } +} + +public postfix func .+( + _ component: Component +) -> OneOrMore<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) +} + + +extension Repeat { + public init( + _ component: Component, + count: Int + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + } + + public init( + count: Int, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + assert(count > 0, "Must specify a positive count") + // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` + self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + } + + public init( + _ component: Component, + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( + _ expression: R, + _ behavior: QuantificationBehavior = .eagerly, + @RegexComponentBuilder _ component: () -> Component + ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { + self.init(node: .repeating(expression.relative(to: 0..( - combining next: R1, into combined: R0 - ) -> Regex where R0: RegexProtocol, R1: RegexProtocol { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf where R0: RegexComponent, R1: RegexComponent { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex where R0: RegexProtocol, R1: RegexProtocol { +public func | (lhs: R0, rhs: R1) -> ChoiceOf where R0: RegexComponent, R1: RegexComponent { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0?, C1?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0?, C1?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?, C1?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0?, C1?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0?, C1?, C2?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0?, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?, C1?, C2?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0?, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R1.Output == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1?, C2?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1?, C2?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1?, C2?, C3?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1?, C2?, C3?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0), R1.Output == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2?, C3?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2?, C3?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2?, C3?, C4?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2?, C3?, C4?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2?, C3?, C4?, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2?, C3?, C4?, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7, C8) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7, C8) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1), R1.Output == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3?, C4?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3?, C4?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3?, C4?, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3?, C4?, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7, C8) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7, C8) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7, C8, C9) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2), R1.Output == (W1, C3, C4, C5, C6, C7, C8, C9) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4?, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4?, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4?, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4?, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7, C8) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7, C8) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7, C8, C9) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3), R1.Output == (W1, C4, C5, C6, C7, C8, C9) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5?, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7, C8) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7, C8) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7, C8) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7, C8, C9) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7, C8, C9) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4), R1.Output == (W1, C5, C6, C7, C8, C9) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7, C8) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7, C8) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7, C8) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7, C8) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7, C8, C9) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7, C8, C9) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7, C8, C9) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5), R1.Output == (W1, C6, C7, C8, C9) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7, C8) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7, C8) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7, C8) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7, C8) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7, C8, C9) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7, C8, C9) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7, C8, C9) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Output == (W1, C7, C8, C9) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Match == (W1, C8) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (W1, C8) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Match == (W1, C8) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (W1, C8) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Match == (W1, C8, C9) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (W1, C8, C9) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Match == (W1, C8, C9) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Output == (W1, C8, C9) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock( - combining next: R1, into combined: R0 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.Match == (W1, C9) { - .init(node: combined.regex.root.appendingAlternationCase(next.regex.root)) + public static func buildPartialBlock( + accumulated: R0, next: R1 + ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.Output == (W1, C9) { + .init(node: accumulated.regex.root.appendingAlternationCase(next.regex.root)) } } -public func | (lhs: R0, rhs: R1) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9?)> where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.Match == (W1, C9) { +public func | (lhs: R0, rhs: R1) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.Output == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.Output == (W1, C9) { .init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root)) } extension AlternationBuilder { - public static func buildBlock(_ regex: R) -> Regex<(W, C0?)> where R: RegexProtocol, R.Match == (W, C0) { - .init(node: .alternation([regex.regex.root])) + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?)> where R: RegexComponent, R.Output == (W, C0) { + .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildBlock(_ regex: R) -> Regex<(W, C0?, C1?)> where R: RegexProtocol, R.Match == (W, C0, C1) { - .init(node: .alternation([regex.regex.root])) + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?)> where R: RegexComponent, R.Output == (W, C0, C1) { + .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildBlock(_ regex: R) -> Regex<(W, C0?, C1?, C2?)> where R: RegexProtocol, R.Match == (W, C0, C1, C2) { - .init(node: .alternation([regex.regex.root])) + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?)> where R: RegexComponent, R.Output == (W, C0, C1, C2) { + .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildBlock(_ regex: R) -> Regex<(W, C0?, C1?, C2?, C3?)> where R: RegexProtocol, R.Match == (W, C0, C1, C2, C3) { - .init(node: .alternation([regex.regex.root])) + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3) { + .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildBlock(_ regex: R) -> Regex<(W, C0?, C1?, C2?, C3?, C4?)> where R: RegexProtocol, R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .alternation([regex.regex.root])) + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4) { + .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildBlock(_ regex: R) -> Regex<(W, C0?, C1?, C2?, C3?, C4?, C5?)> where R: RegexProtocol, R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .alternation([regex.regex.root])) + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4, C5) { + .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildBlock(_ regex: R) -> Regex<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R: RegexProtocol, R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .alternation([regex.regex.root])) + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildBlock(_ regex: R) -> Regex<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R: RegexProtocol, R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .alternation([regex.regex.root])) + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + .init(node: .orderedChoice([regex.regex.root])) } } extension AlternationBuilder { - public static func buildBlock(_ regex: R) -> Regex<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R: RegexProtocol, R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .alternation([regex.regex.root])) + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + .init(node: .orderedChoice([regex.regex.root])) + } +} +extension AlternationBuilder { + public static func buildPartialBlock(first regex: R) -> ChoiceOf<(W, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R: RegexComponent, R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + .init(node: .orderedChoice([regex.regex.root])) } } // MARK: - Non-builder capture arity 0 -public func capture( - _ component: R -) -> Regex<(Substring, W)> where R.Match == W { - .init(node: .group(.capture, component.regex.root)) -} - -public func capture( - _ component: R, as reference: Reference -) -> Regex<(Substring, W)> where R.Match == W { - .init(node: .group(.capture, component.regex.root, reference.id)) -} - -public func capture( - _ component: R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture)> where R.Match == W { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func capture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture)> where R.Match == W { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture)> where R.Match == W { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture)> where R.Match == W { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture)> where R.Match == W { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture)> where R.Match == W { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + @_disfavoredOverload + public init( + _ component: R + ) where Output == (Substring, W), R.Output == W { + self.init(node: .capture(component.regex.root)) + } + + @_disfavoredOverload + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W), R.Output == W { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + @_disfavoredOverload + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + @_disfavoredOverload + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + @_disfavoredOverload + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + @_disfavoredOverload + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + @_disfavoredOverload + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + @_disfavoredOverload + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity 0 -public func capture( - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W)> where R.Match == W { - .init(node: .group(.capture, component().regex.root)) -} - -public func capture( - as reference: Reference, - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W)> where R.Match == W { - .init(node: .group(.capture, component().regex.root, reference.id)) -} - -public func capture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture)> where R.Match == W { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture)> where R.Match == W { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture)> where R.Match == W { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture)> where R.Match == W { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + @_disfavoredOverload + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W), R.Output == W { + self.init(node: .capture(component().regex.root)) + } + + @_disfavoredOverload + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W), R.Output == W { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + @_disfavoredOverload + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + @_disfavoredOverload + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + @_disfavoredOverload + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + @_disfavoredOverload + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + @_disfavoredOverload + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + @_disfavoredOverload + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture), R.Output == W { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } // MARK: - Non-builder capture arity 1 -public func capture( - _ component: R -) -> Regex<(Substring, W, C0)> where R.Match == (W, C0) { - .init(node: .group(.capture, component.regex.root)) -} - -public func capture( - _ component: R, as reference: Reference -) -> Regex<(Substring, W, C0)> where R.Match == (W, C0) { - .init(node: .group(.capture, component.regex.root, reference.id)) -} - -public func capture( - _ component: R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0)> where R.Match == (W, C0) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func capture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0)> where R.Match == (W, C0) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0)> where R.Match == (W, C0) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0)> where R.Match == (W, C0) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0)> where R.Match == (W, C0) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0)> where R.Match == (W, C0) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W, C0), R.Output == (W, C0) { + self.init(node: .capture(component.regex.root)) + } + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W, C0), R.Output == (W, C0) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity 1 -public func capture( - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0)> where R.Match == (W, C0) { - .init(node: .group(.capture, component().regex.root)) -} - -public func capture( - as reference: Reference, - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0)> where R.Match == (W, C0) { - .init(node: .group(.capture, component().regex.root, reference.id)) -} - -public func capture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0)> where R.Match == (W, C0) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0)> where R.Match == (W, C0) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0)> where R.Match == (W, C0) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0)> where R.Match == (W, C0) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0), R.Output == (W, C0) { + self.init(node: .capture(component().regex.root)) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0), R.Output == (W, C0) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0), R.Output == (W, C0) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } // MARK: - Non-builder capture arity 2 -public func capture( - _ component: R -) -> Regex<(Substring, W, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .group(.capture, component.regex.root)) -} - -public func capture( - _ component: R, as reference: Reference -) -> Regex<(Substring, W, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .group(.capture, component.regex.root, reference.id)) -} - -public func capture( - _ component: R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func capture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture(component.regex.root)) + } + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity 2 -public func capture( - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .group(.capture, component().regex.root)) -} - -public func capture( - as reference: Reference, - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .group(.capture, component().regex.root, reference.id)) -} - -public func capture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1)> where R.Match == (W, C0, C1) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture(component().regex.root)) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1), R.Output == (W, C0, C1) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } // MARK: - Non-builder capture arity 3 -public func capture( - _ component: R -) -> Regex<(Substring, W, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .group(.capture, component.regex.root)) -} - -public func capture( - _ component: R, as reference: Reference -) -> Regex<(Substring, W, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .group(.capture, component.regex.root, reference.id)) -} - -public func capture( - _ component: R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func capture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture(component.regex.root)) + } + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity 3 -public func capture( - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .group(.capture, component().regex.root)) -} - -public func capture( - as reference: Reference, - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .group(.capture, component().regex.root, reference.id)) -} - -public func capture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2)> where R.Match == (W, C0, C1, C2) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture(component().regex.root)) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2), R.Output == (W, C0, C1, C2) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } // MARK: - Non-builder capture arity 4 -public func capture( - _ component: R -) -> Regex<(Substring, W, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .group(.capture, component.regex.root)) -} - -public func capture( - _ component: R, as reference: Reference -) -> Regex<(Substring, W, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .group(.capture, component.regex.root, reference.id)) -} - -public func capture( - _ component: R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func capture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture(component.regex.root)) + } + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity 4 -public func capture( - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .group(.capture, component().regex.root)) -} - -public func capture( - as reference: Reference, - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .group(.capture, component().regex.root, reference.id)) -} - -public func capture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3)> where R.Match == (W, C0, C1, C2, C3) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture(component().regex.root)) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3), R.Output == (W, C0, C1, C2, C3) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } // MARK: - Non-builder capture arity 5 -public func capture( - _ component: R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .group(.capture, component.regex.root)) -} - -public func capture( - _ component: R, as reference: Reference -) -> Regex<(Substring, W, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .group(.capture, component.regex.root, reference.id)) -} - -public func capture( - _ component: R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func capture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture(component.regex.root)) + } + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity 5 -public func capture( - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .group(.capture, component().regex.root)) -} - -public func capture( - as reference: Reference, - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .group(.capture, component().regex.root, reference.id)) -} - -public func capture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4)> where R.Match == (W, C0, C1, C2, C3, C4) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture(component().regex.root)) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4), R.Output == (W, C0, C1, C2, C3, C4) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } // MARK: - Non-builder capture arity 6 -public func capture( - _ component: R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .group(.capture, component.regex.root)) -} - -public func capture( - _ component: R, as reference: Reference -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .group(.capture, component.regex.root, reference.id)) -} - -public func capture( - _ component: R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func capture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture(component.regex.root)) + } + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, 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))) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity 6 -public func capture( - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .group(.capture, component().regex.root)) -} - -public func capture( - as reference: Reference, - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .group(.capture, component().regex.root, reference.id)) -} - -public func capture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5)> where R.Match == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture(component().regex.root)) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, 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))) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5), R.Output == (W, C0, C1, C2, C3, C4, C5) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } // MARK: - Non-builder capture arity 7 -public func capture( - _ component: R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .group(.capture, component.regex.root)) -} - -public func capture( - _ component: R, as reference: Reference -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .group(.capture, component.regex.root, reference.id)) -} - -public func capture( - _ component: R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func capture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture(component.regex.root)) + } + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, 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))) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity 7 -public func capture( - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .group(.capture, component().regex.root)) -} - -public func capture( - as reference: Reference, - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .group(.capture, component().regex.root, reference.id)) -} - -public func capture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture(component().regex.root)) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, 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))) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6), R.Output == (W, C0, C1, C2, C3, C4, C5, C6) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } // MARK: - Non-builder capture arity 8 -public func capture( - _ component: R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .group(.capture, component.regex.root)) -} - -public func capture( - _ component: R, as reference: Reference -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .group(.capture, component.regex.root, reference.id)) -} - -public func capture( - _ component: R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func capture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture(component.regex.root)) + } + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, 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))) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity 8 -public func capture( - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .group(.capture, component().regex.root)) -} - -public func capture( - as reference: Reference, - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .group(.capture, component().regex.root, reference.id)) -} - -public func capture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture(component().regex.root)) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + try transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, 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))) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } // MARK: - Non-builder capture arity 9 -public func capture( - _ component: R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .group(.capture, component.regex.root)) -} - -public func capture( - _ component: R, as reference: Reference -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .group(.capture, component.regex.root, reference.id)) -} - -public func capture( - _ component: R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func capture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - _ component: R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - _ component: R, - as reference: Reference, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .groupTransform( - .capture, - component.regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture(component.regex.root)) + } + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, 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))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, 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))) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } } // MARK: - Builder capture arity 9 -public func capture( - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .group(.capture, component().regex.root)) -} - -public func capture( - as reference: Reference, - @RegexBuilder _ component: () -> R -) -> Regex<(Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .group(.capture, component().regex.root, reference.id)) -} - -public func capture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) throws -> NewCapture -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - try transform($0) as Any - }, - reference.id)) -} - -public func tryCapture( - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - })) -} - -public func tryCapture( - as reference: Reference, - @RegexBuilder _ component: () -> R, - transform: @escaping (Substring) -> NewCapture? -) -> Regex<(Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R.Match == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .groupTransform( - .capture, - component().regex.root, - CaptureTransform(resultType: NewCapture.self) { - transform($0) as Any? - }, - reference.id)) +extension Capture { + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture(component().regex.root)) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, 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))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, 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))) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } +} + +// MARK: - Non-builder capture arity 10 + +extension Capture { + public init( + _ component: R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture(component.regex.root)) + } + + public init( + _ component: R, as reference: Reference + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture(reference: reference.id, component.regex.root)) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component.regex.root))) + } +} + +extension TryCapture { + public init( + _ component: R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, 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))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, 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))) + } + + public init( + _ component: R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } + + public init( + _ component: R, + as reference: Reference, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component.regex.root))) + } +} + +// MARK: - Builder capture arity 10 + +extension Capture { + public init( + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture(component().regex.root)) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R + ) where Output == (Substring, W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture( + reference: reference.id, + component().regex.root)) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any + }, + component().regex.root))) + } +} + +extension TryCapture { + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, 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))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) throws -> NewCapture + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, 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))) + } + + public init( + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture(.transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } + + public init( + as reference: Reference, + @RegexComponentBuilder _ component: () -> R, + transform: @escaping (Substring) -> NewCapture? + ) where Output == (Substring, NewCapture, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + self.init(node: .capture( + reference: reference.id, + .transform( + CaptureTransform(resultType: NewCapture.self) { + transform($0) as Any? + }, + component().regex.root))) + } } diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index 7d1ade03e..6a7bf646b 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -116,13 +116,13 @@ class RegexConsumerTests: XCTestCase { } func testMatches() { - let regex = capture(oneOrMore(.digit)) { 2 * Int($0)! } + let regex = Capture(OneOrMore(.digit)) { 2 * Int($0)! } let str = "foo 160 bar 99 baz" XCTAssertEqual(str.matches(of: regex).map(\.result.1), [320, 198]) } func testMatchReplace() { - func replaceTest( + func replaceTest( _ regex: R, input: String, result: String, @@ -133,7 +133,7 @@ class RegexConsumerTests: XCTestCase { XCTAssertEqual(input.replacing(regex, with: replace), result) } - let int = capture(oneOrMore(.digit)) { Int($0)! } + let int = Capture(OneOrMore(.digit)) { Int($0)! } replaceTest( int, @@ -149,13 +149,13 @@ class RegexConsumerTests: XCTestCase { // TODO: Need to support capture history // replaceTest( - // oneOrMore { int; "," }, + // OneOrMore { int; "," }, // input: "3,5,8,0, 1,0,2,-5,x8,8,", // result: "16 3-5x16", // { match in "\(match.result.1.reduce(0, +))" }) replaceTest( - Regex { int; "x"; int; optionally { "x"; int } }, + Regex { int; "x"; int; Optionally { "x"; int } }, input: "2x3 5x4x3 6x0 1x2x3x4", result: "6 60 0 6x4", { match in "\(match.result.1 * match.result.2 * (match.result.3 ?? 1))" }) diff --git a/Tests/RegexTests/CustomTests.swift b/Tests/RegexTests/CustomTests.swift index 0ebfe4652..12d4ad6cd 100644 --- a/Tests/RegexTests/CustomTests.swift +++ b/Tests/RegexTests/CustomTests.swift @@ -3,7 +3,7 @@ import XCTest // A nibbler processes a single character from a string private protocol Nibbler: CustomRegexComponent { - func nibble(_: Character) -> Match? + func nibble(_: Character) -> Output? } extension Nibbler { @@ -12,7 +12,7 @@ extension Nibbler { _ input: String, startingAt index: String.Index, in bounds: Range - ) -> (upperBound: String.Index, match: Match)? { + ) -> (upperBound: String.Index, output: Output)? { guard index != bounds.upperBound, let res = nibble(input[index]) else { return nil } @@ -23,7 +23,7 @@ extension Nibbler { // A number nibbler private struct Numbler: Nibbler { - typealias Match = Int + typealias Output = Int func nibble(_ c: Character) -> Int? { c.wholeNumberValue } @@ -31,7 +31,7 @@ private struct Numbler: Nibbler { // An ASCII value nibbler private struct Asciibbler: Nibbler { - typealias Match = UInt8 + typealias Output = UInt8 func nibble(_ c: Character) -> UInt8? { c.asciiValue } @@ -50,7 +50,7 @@ func customTest( let result: Match? switch call { case .match: - result = input.match(regex)?.match + result = input.match(regex)?.output case .firstMatch: result = input.firstMatch(of: regex)?.result } @@ -76,7 +76,7 @@ extension RegexTests { customTest( Regex { - oneOrMore { Numbler() } + OneOrMore { Numbler() } }, ("ab123c", .firstMatch, "123"), ("abc", .firstMatch, nil), @@ -97,8 +97,8 @@ extension RegexTests { // `Equatable` which tuples cannot be. let regex3 = Regex { - capture { - oneOrMore { + Capture { + OneOrMore { Numbler() } } @@ -114,8 +114,8 @@ extension RegexTests { XCTAssertEqual(res3.result.1, "123") let regex4 = Regex { - oneOrMore { - capture { Numbler() } + OneOrMore { + Capture { Numbler() } } } diff --git a/Tests/RegexTests/RegexDSLTests.swift b/Tests/RegexTests/RegexDSLTests.swift index d78ff04e5..4ca446b32 100644 --- a/Tests/RegexTests/RegexDSLTests.swift +++ b/Tests/RegexTests/RegexDSLTests.swift @@ -12,27 +12,27 @@ import XCTest @testable import _StringProcessing -func dynCap( - _ s: String, optional: Bool = false -) -> StoredDynamicCapture { - StoredDynamicCapture(s[...], optionalCount: optional ? 1 : 0) -} - class RegexDSLTests: XCTestCase { - func _testDSLCaptures( - _ tests: (input: String, expectedCaptures: CaptureType?)..., - matchType: CaptureType.Type, - _ equivalence: (CaptureType, CaptureType) -> Bool, + func _testDSLCaptures( + _ tests: (input: String, expectedCaptures: MatchType?)..., + matchType: MatchType.Type, + _ equivalence: (MatchType, MatchType) -> Bool, file: StaticString = #file, line: UInt = #line, - @RegexBuilder _ content: () -> Content + @RegexComponentBuilder _ content: () -> Content ) throws { let regex = Regex(content()) for (input, maybeExpectedCaptures) in tests { let maybeMatch = input.match(regex) if let expectedCaptures = maybeExpectedCaptures { let match = try XCTUnwrap(maybeMatch, file: file, line: line) - let captures = try XCTUnwrap(match.match as? CaptureType, file: file, line: line) + XCTAssertTrue( + type(of: regex).Output.self == MatchType.self, + """ + Expected match type: \(MatchType.self) + Actual match type: \(type(of: regex).Output.self) + """) + let captures = try XCTUnwrap(match.output as? MatchType, file: file, line: line) XCTAssertTrue( equivalence(captures, expectedCaptures), "'\(captures)' is not equal to the expected '\(expectedCaptures)'.", @@ -46,18 +46,18 @@ class RegexDSLTests: XCTestCase { func testSimpleStrings() throws { let regex = Regex { "a" - capture(Character("b")) // Character - tryCapture("1") { Int($0) } // Int + Capture(Character("b")) // Character + TryCapture("1") { Int($0) } // Int } // Assert the inferred capture type. - let _: (Substring, Substring, Int).Type = type(of: regex).Match.self + let _: (Substring, Substring, Int).Type = type(of: regex).Output.self let maybeMatch = "ab1".match(regex) let match = try XCTUnwrap(maybeMatch) - XCTAssertTrue(match.match == ("ab1", "b", 1)) + XCTAssertTrue(match.output == ("ab1", "b", 1)) let substring = "ab1"[...] let substringMatch = try XCTUnwrap(substring.match(regex)) - XCTAssertTrue(match.match == substringMatch.match) + XCTAssertTrue(match.output == substringMatch.output) } func testCharacterClasses() throws { @@ -66,95 +66,95 @@ class RegexDSLTests: XCTestCase { matchType: (Substring, Substring, Substring).self, ==) { .any - capture(.whitespace) // Substring - capture("c") // Substring + Capture(.whitespace) // Substring + Capture("c") // Substring } } func testMatchResultDotZeroWithoutCapture() throws { - let match = try XCTUnwrap("aaa".match { oneOrMore { "a" } }) + let match = try XCTUnwrap("aaa".match { OneOrMore { "a" } }) XCTAssertEqual(match.0, "aaa") } func testAlternation() throws { do { - let regex = choiceOf { + let regex = ChoiceOf { "aaa" } - XCTAssertTrue("aaa".match(regex)?.match == "aaa") - XCTAssertNil("aab".match(regex)?.match) + XCTAssertTrue("aaa".match(regex)?.output == "aaa") + XCTAssertNil("aab".match(regex)?.output) } do { - let regex = choiceOf { + let regex = ChoiceOf { "aaa" "bbb" "ccc" } - XCTAssertTrue("aaa".match(regex)?.match == "aaa") - XCTAssertNil("aab".match(regex)?.match) - XCTAssertTrue("bbb".match(regex)?.match == "bbb") - XCTAssertTrue("ccc".match(regex)?.match == "ccc") + XCTAssertTrue("aaa".match(regex)?.output == "aaa") + XCTAssertNil("aab".match(regex)?.output) + XCTAssertTrue("bbb".match(regex)?.output == "bbb") + XCTAssertTrue("ccc".match(regex)?.output == "ccc") } do { let regex = Regex { "ab" - capture { - choiceOf { + Capture { + ChoiceOf { "c" "def" } }.+ } XCTAssertTrue( - try XCTUnwrap("abc".match(regex)?.match) == ("abc", "c")) + try XCTUnwrap("abc".match(regex)?.output) == ("abc", "c")) } do { - let regex = choiceOf { + let regex = ChoiceOf { "aaa" "bbb" "ccc" } - XCTAssertTrue("aaa".match(regex)?.match == "aaa") - XCTAssertNil("aab".match(regex)?.match) - XCTAssertTrue("bbb".match(regex)?.match == "bbb") - XCTAssertTrue("ccc".match(regex)?.match == "ccc") + XCTAssertTrue("aaa".match(regex)?.output == "aaa") + XCTAssertNil("aab".match(regex)?.output) + XCTAssertTrue("bbb".match(regex)?.output == "bbb") + XCTAssertTrue("ccc".match(regex)?.output == "ccc") } do { - let regex = choiceOf { - capture("aaa") + let regex = ChoiceOf { + Capture("aaa") } XCTAssertTrue( - try XCTUnwrap("aaa".match(regex)?.match) == ("aaa", "aaa")) - XCTAssertNil("aab".match(regex)?.match) + try XCTUnwrap("aaa".match(regex)?.output) == ("aaa", "aaa")) + XCTAssertNil("aab".match(regex)?.output) } do { - let regex = choiceOf { - capture("aaa") - capture("bbb") - capture("ccc") + let regex = ChoiceOf { + Capture("aaa") + Capture("bbb") + Capture("ccc") } XCTAssertTrue( - try XCTUnwrap("aaa".match(regex)?.match) == ("aaa", "aaa", nil, nil)) + try XCTUnwrap("aaa".match(regex)?.output) == ("aaa", "aaa", nil, nil)) XCTAssertTrue( - try XCTUnwrap("bbb".match(regex)?.match) == ("bbb", nil, "bbb", nil)) + try XCTUnwrap("bbb".match(regex)?.output) == ("bbb", nil, "bbb", nil)) XCTAssertTrue( - try XCTUnwrap("ccc".match(regex)?.match) == ("ccc", nil, nil, "ccc")) - XCTAssertNil("aab".match(regex)?.match) + try XCTUnwrap("ccc".match(regex)?.output) == ("ccc", nil, nil, "ccc")) + XCTAssertNil("aab".match(regex)?.output) } } func testCombinators() throws { try _testDSLCaptures( ("aaaabccccdddkj", ("aaaabccccdddkj", "b", "cccc", "d", "k", nil, "j")), - matchType: (Substring, Substring, Substring, Substring, Substring, Substring?, Substring?).self, ==) + matchType: (Substring, Substring, Substring, Substring?, Substring, Substring?, Substring?).self, ==) { "a".+ - capture(oneOrMore(Character("b"))) // Substring - capture(zeroOrMore("c")) // Substring - capture(.hexDigit).* // [Substring] + Capture(OneOrMore(Character("b"))) // Substring + Capture(ZeroOrMore("c")) // Substring + Capture(.hexDigit).* // Substring? "e".? - capture("t" | "k") // Substring - choiceOf { capture("k"); capture("j") } // (Substring?, Substring?) + Capture("t" | "k") // Substring + ChoiceOf { Capture("k"); Capture("j") } // (Substring?, Substring?) } } @@ -165,7 +165,7 @@ class RegexDSLTests: XCTestCase { ("abcabc", "abcabc"), ("abcABCaBc", "abcABCaBc"), matchType: Substring.self, ==) { - oneOrMore { + OneOrMore { "abc" }.caseSensitive(false) } @@ -178,7 +178,7 @@ class RegexDSLTests: XCTestCase { ("abcabc", "abcabc"), ("abcABCaBc", "abcABCaBc"), matchType: Substring.self, ==) { - oneOrMore { + OneOrMore { "abc" } .caseSensitive(false) @@ -195,9 +195,9 @@ class RegexDSLTests: XCTestCase { ("abcabc", "abcabc"), ("abcdeABCdeaBcde", "abcdeABCdeaBcde"), matchType: Substring.self, ==) { - oneOrMore { + OneOrMore { "abc".caseSensitive(false) - optionally("de") + Optionally("de") } .caseSensitive(true) } @@ -208,9 +208,9 @@ class RegexDSLTests: XCTestCase { ("abc1def2", ("abc1def2", "2")), matchType: (Substring, Substring).self, ==) { - oneOrMore { - oneOrMore(.word) - capture(.digit) + OneOrMore { + OneOrMore(.word) + Capture(.digit) } } @@ -218,9 +218,9 @@ class RegexDSLTests: XCTestCase { ("abc1def2", ("abc1def2", "2")), matchType: (Substring, Substring).self, ==) { - oneOrMore { - oneOrMore(.word, .reluctantly) - capture(.digit) + OneOrMore { + OneOrMore(.word, .reluctantly) + Capture(.digit) } } @@ -228,11 +228,11 @@ class RegexDSLTests: XCTestCase { ("abc1def2", ("abc1def2", "2")), matchType: (Substring, Substring).self, ==) { - oneOrMore { - oneOrMore(.reluctantly) { + OneOrMore { + OneOrMore(.reluctantly) { .word } - capture(.digit) + Capture(.digit) } } @@ -240,8 +240,8 @@ class RegexDSLTests: XCTestCase { ("abc1def2", "abc1def2"), matchType: Substring.self, ==) { - repeating(2...) { - repeating(count: 3) { + Repeat(2...) { + Repeat(count: 3) { CharacterClass.word } CharacterClass.digit @@ -258,12 +258,12 @@ class RegexDSLTests: XCTestCase { ("aaabbbcccdddeee", "aaabbbcccdddeee"), matchType: Substring.self, ==) { - repeating(count: 3) { "a" } - repeating(1...) { "b" } - repeating(2...5) { "c" } - repeating(..<5) { "d" } - repeating(2...) { "e" } - repeating(0...) { "f" } + Repeat(count: 3) { "a" } + Repeat(1...) { "b" } + Repeat(2...5) { "c" } + Repeat(..<5) { "d" } + Repeat(2...) { "e" } + Repeat(0...) { "f" } } } @@ -285,7 +285,7 @@ class RegexDSLTests: XCTestCase { ("Cafe", "Cafe"), matchType: Substring.self, ==) { - oneOrMore(.word) + OneOrMore(.word) UnicodeScalar("e") Anchor.textSegmentBoundary } @@ -315,10 +315,10 @@ class RegexDSLTests: XCTestCase { matchType: (Substring, [(Substring, Substring, [Substring])]).self, ==) { "a".+ - oneOrMore { - capture(oneOrMore("b")) - capture(zeroOrMore("c")) - capture("d").* + OneOrMore { + Capture(OneOrMore("b")) + Capture(ZeroOrMore("c")) + Capture("d").* "e".? } } @@ -330,11 +330,11 @@ class RegexDSLTests: XCTestCase { // straight out of the quantifier (without being wrapped in a builder), is // able to produce a regex whose `Match` type does not contain any sort of // void. - let regex = zeroOrMore(.digit) + let regex = ZeroOrMore(.digit) // Assert the inferred capture type. - let _: Substring.Type = type(of: regex).Match.self + let _: Substring.Type = type(of: regex).Output.self let input = "123123" - let match = try XCTUnwrap(input.match(regex)?.match) + let match = try XCTUnwrap(input.match(regex)?.output) XCTAssertTrue(match == input) } @@ -361,13 +361,13 @@ class RegexDSLTests: XCTestCase { matchType: (Substring, Int?, Word?).self, ==) { "a".+ - oneOrMore(.whitespace) - optionally { - capture(oneOrMore(.digit)) { Int($0)! } + OneOrMore(.whitespace) + Optionally { + Capture(OneOrMore(.digit)) { Int($0)! } } - zeroOrMore { - oneOrMore(.whitespace) - capture(oneOrMore(.word)) { Word($0)! } + ZeroOrMore { + OneOrMore(.whitespace) + Capture(OneOrMore(.word)) { Word($0)! } } } } @@ -375,59 +375,59 @@ class RegexDSLTests: XCTestCase { func testNestedCaptureTypes() throws { let regex1 = Regex { "a".+ - capture { - capture(oneOrMore("b")) + Capture { + Capture(OneOrMore("b")) "e".? } } let _: (Substring, Substring, Substring).Type - = type(of: regex1).Match.self + = type(of: regex1).Output.self let regex2 = Regex { "a".+ - capture { - tryCapture("b") { Int($0) }.* + Capture { + TryCapture("b") { Int($0) }.* "e".? } } let _: (Substring, Substring, Int?).Type - = type(of: regex2).Match.self + = type(of: regex2).Output.self let regex3 = Regex { "a".+ - capture { - tryCapture("b") { Int($0) } - zeroOrMore { - tryCapture("c") { Double($0) } + Capture { + TryCapture("b") { Int($0) } + ZeroOrMore { + TryCapture("c") { Double($0) } } "e".? } } let _: (Substring, Substring, Int, Double?).Type - = type(of: regex3).Match.self + = type(of: regex3).Output.self let regex4 = Regex { "a".+ - capture { - oneOrMore { - capture(oneOrMore("b")) - capture(zeroOrMore("c")) - capture("d").* + Capture { + OneOrMore { + Capture(OneOrMore("b")) + Capture(ZeroOrMore("c")) + Capture("d").* "e".? } } } let _: ( Substring, Substring, Substring, Substring, Substring?).Type - = type(of: regex4).Match.self + = type(of: regex4).Output.self } func testUnicodeScalarPostProcessing() throws { let spaces = Regex { - zeroOrMore { + ZeroOrMore { .whitespace } } let unicodeScalar = Regex { - oneOrMore { + OneOrMore { .hexDigit } spaces @@ -435,7 +435,7 @@ class RegexDSLTests: XCTestCase { let unicodeData = Regex { unicodeScalar - optionally { + Optionally { ".." unicodeScalar } @@ -443,19 +443,19 @@ class RegexDSLTests: XCTestCase { ";" spaces - capture { - oneOrMore { + Capture { + OneOrMore { .word } } - zeroOrMore { + ZeroOrMore { .any } } // Assert the inferred capture type. - let _: (Substring, Substring).Type = type(of: unicodeData).Match.self + let _: (Substring, Substring).Type = type(of: unicodeData).Output.self let unicodeLine = "1BCA0..1BCA3 ; Control # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP" @@ -470,30 +470,30 @@ class RegexDSLTests: XCTestCase { """ let regexWithCapture = Regex { - capture { - oneOrMore(.hexDigit) + Capture { + OneOrMore(.hexDigit) } transform: { Unicode.Scalar(hex: $0) } - optionally { + Optionally { ".." - capture { - oneOrMore(.hexDigit) + Capture { + OneOrMore(.hexDigit) } transform: { Unicode.Scalar(hex: $0) } } - oneOrMore(.whitespace) + OneOrMore(.whitespace) ";" - oneOrMore(.whitespace) - capture(oneOrMore(.word)) - zeroOrMore(.any) + OneOrMore(.whitespace) + Capture(OneOrMore(.word)) + ZeroOrMore(.any) } // Regex<(Substring, Unicode.Scalar?, Unicode.Scalar??, Substring)> do { // Assert the inferred capture type. typealias ExpectedMatch = ( Substring, Unicode.Scalar?, Unicode.Scalar??, Substring ) - let _: ExpectedMatch.Type = type(of: regexWithCapture).Match.self + let _: ExpectedMatch.Type = type(of: regexWithCapture).Output.self let maybeMatchResult = line.match(regexWithCapture) let matchResult = try XCTUnwrap(maybeMatchResult) - let (wholeMatch, lower, upper, propertyString) = matchResult.match + let (wholeMatch, lower, upper, propertyString) = matchResult.output XCTAssertEqual(wholeMatch, Substring(line)) XCTAssertEqual(lower, Unicode.Scalar(0xA6F0)) XCTAssertEqual(upper, Unicode.Scalar(0xA6F1)) @@ -501,34 +501,34 @@ class RegexDSLTests: XCTestCase { } let regexWithTryCapture = Regex { - tryCapture { - oneOrMore(.hexDigit) + TryCapture { + OneOrMore(.hexDigit) } transform: { Unicode.Scalar(hex: $0) } - optionally { + Optionally { ".." - tryCapture { - oneOrMore(.hexDigit) + TryCapture { + OneOrMore(.hexDigit) } transform: { Unicode.Scalar(hex: $0) } } - oneOrMore(.whitespace) + OneOrMore(.whitespace) ";" - oneOrMore(.whitespace) - capture(oneOrMore(.word)) - zeroOrMore(.any) + OneOrMore(.whitespace) + Capture(OneOrMore(.word)) + ZeroOrMore(.any) } // Regex<(Substring, Unicode.Scalar, Unicode.Scalar?, Substring)> do { // Assert the inferred capture type. typealias ExpectedMatch = ( Substring, Unicode.Scalar, Unicode.Scalar?, Substring ) - let _: ExpectedMatch.Type = type(of: regexWithTryCapture).Match.self + let _: ExpectedMatch.Type = type(of: regexWithTryCapture).Output.self let maybeMatchResult = line.match(regexWithTryCapture) let matchResult = try XCTUnwrap(maybeMatchResult) - let (wholeMatch, lower, upper, propertyString) = matchResult.match + let (wholeMatch, lower, upper, propertyString) = matchResult.output XCTAssertEqual(wholeMatch, Substring(line)) XCTAssertEqual(lower, Unicode.Scalar(0xA6F0)) XCTAssertEqual(upper, Unicode.Scalar(0xA6F1)) @@ -541,7 +541,7 @@ class RegexDSLTests: XCTestCase { matching: (Substring, Substring, Substring?, Substring).self) let maybeMatchResult = line.match(regexLiteral) let matchResult = try XCTUnwrap(maybeMatchResult) - let (wholeMatch, lower, upper, propertyString) = matchResult.match + let (wholeMatch, lower, upper, propertyString) = matchResult.output XCTAssertEqual(wholeMatch, Substring(line)) XCTAssertEqual(lower, "A6F0") XCTAssertEqual(upper, "A6F1") @@ -553,25 +553,31 @@ class RegexDSLTests: XCTestCase { do { let regex = try Regex("aabcc.") let line = "aabccd" - let captures = try XCTUnwrap(line.match(regex)?.1) - XCTAssertEqual(captures, []) + let match = try XCTUnwrap(line.match(regex)) + XCTAssertEqual(match.0, line[...]) + let output = match.output + XCTAssertEqual(output[0].substring, line[...]) } do { - let regex = try Regex( #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#) let line = """ A6F0..A6F1 ; Extend # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM \ COMBINING MARK TUKWENTIS """ - let captures = try XCTUnwrap(line.match(regex)?.1) - XCTAssertEqual( - captures, - [ - dynCap("A6F0"), - dynCap("A6F1", optional: true), - dynCap("Extend"), - ]) + let match = try XCTUnwrap(line.match(regex)) + XCTAssertEqual(match.0, line[...]) + let output = match.output + XCTAssertEqual(output[0].substring, line[...]) + XCTAssertTrue(output[1].substring == "A6F0") + XCTAssertTrue(output[2].substring == "A6F1") + XCTAssertTrue(output[3].substring == "Extend") + let typedOutput = try XCTUnwrap(output.as( + (Substring, Substring, Substring?, Substring).self)) + XCTAssertEqual(typedOutput.0, line[...]) + XCTAssertTrue(typedOutput.1 == "A6F0") + XCTAssertTrue(typedOutput.2 == "A6F1") + XCTAssertTrue(typedOutput.3 == "Extend") } } @@ -582,22 +588,22 @@ class RegexDSLTests: XCTestCase { { let a = Reference(Substring.self) let b = Reference(Int.self) - capture("abc", as: a) - zeroOrMore { - tryCapture(as: b) { + Capture("abc", as: a) + ZeroOrMore { + TryCapture(as: b) { "#" - oneOrMore(.digit) + OneOrMore(.digit) } transform: { Int($0.dropFirst()) } } a - zeroOrMore { - capture(a) + ZeroOrMore { + Capture(a) } - optionally { + Optionally { "b" - capture(a) + Capture(a) } } @@ -606,21 +612,21 @@ class RegexDSLTests: XCTestCase { let a = Reference(Substring.self) let b = Reference(Int.self) let regex = Regex { - capture("abc", as: a) - zeroOrMore { - tryCapture(as: b) { + Capture("abc", as: a) + ZeroOrMore { + TryCapture(as: b) { "#" - oneOrMore(.digit) + OneOrMore(.digit) } transform: { Int($0.dropFirst()) } } a - zeroOrMore { - capture(b) + ZeroOrMore { + Capture(b) } - optionally { - capture(a) + Optionally { + Capture(a) } } let input = "abc#41#42abc#42#42" @@ -633,19 +639,21 @@ class RegexDSLTests: XCTestCase { // #"(?:\w\1|:(\w):)+"# try _testDSLCaptures( (":a:baca:o:boco", (":a:baca:o:boco", "o")), - matchType: (Substring, Substring).self, + matchType: (Substring, Substring?).self, == ) { - oneOrMore { + // NOTE: "expression too complex to type check" when inferring the generic + // parameter. + OneOrMore { let a = Reference(Substring.self) - choiceOf { + ChoiceOf<(Substring, Substring?)> { Regex { .word a } Regex { ":" - capture(.word, as: a) + Capture(.word, as: a) ":" } } @@ -661,23 +669,23 @@ class RegexDSLTests: XCTestCase { var dev: String? } struct SemanticVersionParser: CustomRegexComponent { - typealias Match = SemanticVersion + typealias Output = SemanticVersion func match( _ input: String, startingAt index: String.Index, in bounds: Range - ) -> (upperBound: String.Index, match: SemanticVersion)? { + ) -> (upperBound: String.Index, output: SemanticVersion)? { let regex = Regex { - tryCapture(oneOrMore(.digit)) { Int($0) } + TryCapture(OneOrMore(.digit)) { Int($0) } "." - tryCapture(oneOrMore(.digit)) { Int($0) } - optionally { + TryCapture(OneOrMore(.digit)) { Int($0) } + Optionally { "." - tryCapture(oneOrMore(.digit)) { Int($0) } + TryCapture(OneOrMore(.digit)) { Int($0) } } - optionally { + Optionally { "-" - capture(oneOrMore(.word)) + Capture(OneOrMore(.word)) } } @@ -702,7 +710,7 @@ class RegexDSLTests: XCTestCase { let parser = SemanticVersionParser() for (str, version) in versions { - XCTAssertEqual(str.match(parser)?.match, version) + XCTAssertEqual(str.match(parser)?.output, version) } } }