From 71dcbbeada28d331fdd5a9a5cc9decbc601e010a Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Fri, 14 Jan 2022 15:03:40 -0800 Subject: [PATCH] Heterogeneous alternation Introduce `oneOf` combinator, which takes a builder block and joins all elements into a regex alterantion. Fix the legacy VM to support alternation with captures. ----- Example: ```swift oneOf { "a".capture() "b".capture() "c" } => `.Match = (Substring, Substring?, Substring?)` ``` --- .../VariadicsGenerator.swift | 100 ++ .../Legacy/LegacyCompile.swift | 44 +- .../RegexDSL/Concatenation.swift | 1215 +++++++++++++++++ Sources/_StringProcessing/RegexDSL/Core.swift | 8 +- Sources/_StringProcessing/RegexDSL/DSL.swift | 47 +- .../_StringProcessing/RegexDSL/DSLTree.swift | 7 + Tests/RegexTests/RegexDSLTests.swift | 82 +- 7 files changed, 1466 insertions(+), 37 deletions(-) diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index c82f4b1ff..f65fce14e 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -160,6 +160,20 @@ struct VariadicsGenerator: ParsableCommand { print(to: &standardError) } + print("Generating alternation overloads...", to: &standardError) + for (leftArity, rightArity) in Permutations(totalArity: maxArity) { + print( + " Left arity: \(leftArity) Right arity: \(rightArity)", + to: &standardError) + emitAlternation(leftArity: leftArity, rightArity: rightArity) + } + + print("Generating 'AlternationBuilder.buildBlock(_:)' overloads...", to: &standardError) + for arity in 1.. 0 { + result += ", R0.\(matchAssociatedTypeName) == (W0, \((0.. 0 { + result += ", R1.\(matchAssociatedTypeName) == (W1, \((leftArity.. 0, rightArity > 0 { + result += ", " + } + result += (leftArity..: \(regexProtocolName) \(whereClause) { + public typealias Match = \(matchType) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } + } + + extension AlternationBuilder { + public static func buildBlock<\(genericParams)>(combining next: R1, into combined: R0) -> \(typeName)<\(genericParams)> { + .init(combined, next) + } + } + + public func | <\(genericParams)>(lhs: R0, rhs: R1) -> \(typeName)<\(genericParams)> { + .init(lhs, rhs) + } + + """) + } + + func emitUnaryAlternationBuildBlock(arity: Int) { + assert(arity > 0) + let captures = (0..(_ regex: R) -> Regex<(W, \(resultCaptures))> \(whereClause) { + .init(node: .alternation([regex.regex.root])) + } + } + + """) + } } diff --git a/Sources/_StringProcessing/Legacy/LegacyCompile.swift b/Sources/_StringProcessing/Legacy/LegacyCompile.swift index 49009b3f7..ac0ec6a45 100644 --- a/Sources/_StringProcessing/Legacy/LegacyCompile.swift +++ b/Sources/_StringProcessing/Legacy/LegacyCompile.swift @@ -240,22 +240,54 @@ func compile( // E.g. `a` falls-through to the rest of the program and the // other cases branch back. // - assert(!children.isEmpty) - guard children.count > 1 else { - return try compileNode(children[0]) + + // For every capturing child after the child at the given index, emit a + // nil capture. This is used for skipping the remaining alternation + // cases after a succesful match. + func nullifyRest(after index: Int) { + for child in children.suffix(from: index + 1) where child.hasCapture { + instructions.append(contentsOf: [ + .beginGroup, + .captureNil(childType: child.captureStructure.type), + .endGroup, + ]) + } } let last = children.last! let middle = children.dropLast() let done = createLabel() - for child in middle { + for (childIndex, child) in middle.enumerated() { let nextLabel = createLabel() + if child.hasCapture { + instructions.append(.beginGroup) + } instructions.append(.split(disfavoring: nextLabel.label!)) try compileNode(child) - instructions.append(.goto(label: done.label!)) - instructions.append(nextLabel) + if child.hasCapture { + instructions.append(.captureSome) + instructions.append(.endGroup) + } + nullifyRest(after: childIndex) + instructions.append(contentsOf: [ + .goto(label: done.label!), + nextLabel + ]) + if child.hasCapture { + instructions.append(contentsOf: [ + .captureNil(childType: child.captureStructure.type), + .endGroup + ]) + } + } + if last.hasCapture { + instructions.append(.beginGroup) } try compileNode(last) + if last.hasCapture { + instructions.append(.captureSome) + instructions.append(.endGroup) + } instructions.append(done) return diff --git a/Sources/_StringProcessing/RegexDSL/Concatenation.swift b/Sources/_StringProcessing/RegexDSL/Concatenation.swift index c243b68c6..c9672f11a 100644 --- a/Sources/_StringProcessing/RegexDSL/Concatenation.swift +++ b/Sources/_StringProcessing/RegexDSL/Concatenation.swift @@ -2053,6 +2053,1221 @@ public postfix func .*: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol { + public typealias Match = Substring + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_0 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_0 { + .init(lhs, rhs) +} +public struct _Alternation_0_1: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0) { + public typealias Match = (Substring, C0?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_1 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_1 { + .init(lhs, rhs) +} +public struct _Alternation_0_2: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1) { + public typealias Match = (Substring, C0?, C1?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_2 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_2 { + .init(lhs, rhs) +} +public struct _Alternation_0_3: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2) { + public typealias Match = (Substring, C0?, C1?, C2?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_3 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_3 { + .init(lhs, rhs) +} +public struct _Alternation_0_4: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3) { + public typealias Match = (Substring, C0?, C1?, C2?, C3?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_4 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_4 { + .init(lhs, rhs) +} +public struct _Alternation_0_5: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4) { + public typealias Match = (Substring, C0?, C1?, C2?, C3?, C4?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_5 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_5 { + .init(lhs, rhs) +} +public struct _Alternation_0_6: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5) { + public typealias Match = (Substring, C0?, C1?, C2?, C3?, C4?, C5?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_6 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_6 { + .init(lhs, rhs) +} +public struct _Alternation_0_7: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6) { + public typealias Match = (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_7 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_7 { + .init(lhs, rhs) +} +public struct _Alternation_0_8: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { + public typealias Match = (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_8 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_8 { + .init(lhs, rhs) +} +public struct _Alternation_0_9: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + public typealias Match = (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_9 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_9 { + .init(lhs, rhs) +} +public struct _Alternation_0_10: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R1.Match == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public typealias Match = (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_0_10 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_0_10 { + .init(lhs, rhs) +} +public struct _Alternation_1_0: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0) { + public typealias Match = (Substring, C0) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_1_0 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_1_0 { + .init(lhs, rhs) +} +public struct _Alternation_1_1: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1) { + public typealias Match = (Substring, C0, C1?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_1_1 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_1_1 { + .init(lhs, rhs) +} +public struct _Alternation_1_2: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2) { + public typealias Match = (Substring, C0, C1?, C2?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_1_2 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_1_2 { + .init(lhs, rhs) +} +public struct _Alternation_1_3: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3) { + public typealias Match = (Substring, C0, C1?, C2?, C3?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_1_3 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_1_3 { + .init(lhs, rhs) +} +public struct _Alternation_1_4: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4) { + public typealias Match = (Substring, C0, C1?, C2?, C3?, C4?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_1_4 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_1_4 { + .init(lhs, rhs) +} +public struct _Alternation_1_5: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5) { + public typealias Match = (Substring, C0, C1?, C2?, C3?, C4?, C5?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_1_5 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_1_5 { + .init(lhs, rhs) +} +public struct _Alternation_1_6: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6) { + public typealias Match = (Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_1_6 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_1_6 { + .init(lhs, rhs) +} +public struct _Alternation_1_7: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7) { + public typealias Match = (Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_1_7 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_1_7 { + .init(lhs, rhs) +} +public struct _Alternation_1_8: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { + public typealias Match = (Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_1_8 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_1_8 { + .init(lhs, rhs) +} +public struct _Alternation_1_9: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0), R1.Match == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public typealias Match = (Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_1_9 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_1_9 { + .init(lhs, rhs) +} +public struct _Alternation_2_0: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1) { + public typealias Match = (Substring, C0, C1) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_2_0 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_2_0 { + .init(lhs, rhs) +} +public struct _Alternation_2_1: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2) { + public typealias Match = (Substring, C0, C1, C2?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_2_1 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_2_1 { + .init(lhs, rhs) +} +public struct _Alternation_2_2: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3) { + public typealias Match = (Substring, C0, C1, C2?, C3?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_2_2 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_2_2 { + .init(lhs, rhs) +} +public struct _Alternation_2_3: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4) { + public typealias Match = (Substring, C0, C1, C2?, C3?, C4?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_2_3 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_2_3 { + .init(lhs, rhs) +} +public struct _Alternation_2_4: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5) { + public typealias Match = (Substring, C0, C1, C2?, C3?, C4?, C5?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_2_4 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_2_4 { + .init(lhs, rhs) +} +public struct _Alternation_2_5: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6) { + public typealias Match = (Substring, C0, C1, C2?, C3?, C4?, C5?, C6?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_2_5 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_2_5 { + .init(lhs, rhs) +} +public struct _Alternation_2_6: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7) { + public typealias Match = (Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_2_6 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_2_6 { + .init(lhs, rhs) +} +public struct _Alternation_2_7: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7, C8) { + public typealias Match = (Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_2_7 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_2_7 { + .init(lhs, rhs) +} +public struct _Alternation_2_8: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1), R1.Match == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { + public typealias Match = (Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_2_8 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_2_8 { + .init(lhs, rhs) +} +public struct _Alternation_3_0: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2) { + public typealias Match = (Substring, C0, C1, C2) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_3_0 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_3_0 { + .init(lhs, rhs) +} +public struct _Alternation_3_1: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3) { + public typealias Match = (Substring, C0, C1, C2, C3?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_3_1 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_3_1 { + .init(lhs, rhs) +} +public struct _Alternation_3_2: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4) { + public typealias Match = (Substring, C0, C1, C2, C3?, C4?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_3_2 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_3_2 { + .init(lhs, rhs) +} +public struct _Alternation_3_3: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5) { + public typealias Match = (Substring, C0, C1, C2, C3?, C4?, C5?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_3_3 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_3_3 { + .init(lhs, rhs) +} +public struct _Alternation_3_4: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6) { + public typealias Match = (Substring, C0, C1, C2, C3?, C4?, C5?, C6?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_3_4 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_3_4 { + .init(lhs, rhs) +} +public struct _Alternation_3_5: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7) { + public typealias Match = (Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_3_5 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_3_5 { + .init(lhs, rhs) +} +public struct _Alternation_3_6: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7, C8) { + public typealias Match = (Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_3_6 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_3_6 { + .init(lhs, rhs) +} +public struct _Alternation_3_7: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2), R1.Match == (W1, C3, C4, C5, C6, C7, C8, C9) { + public typealias Match = (Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_3_7 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_3_7 { + .init(lhs, rhs) +} +public struct _Alternation_4_0: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3) { + public typealias Match = (Substring, C0, C1, C2, C3) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_4_0 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_4_0 { + .init(lhs, rhs) +} +public struct _Alternation_4_1: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4) { + public typealias Match = (Substring, C0, C1, C2, C3, C4?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_4_1 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_4_1 { + .init(lhs, rhs) +} +public struct _Alternation_4_2: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5) { + public typealias Match = (Substring, C0, C1, C2, C3, C4?, C5?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_4_2 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_4_2 { + .init(lhs, rhs) +} +public struct _Alternation_4_3: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6) { + public typealias Match = (Substring, C0, C1, C2, C3, C4?, C5?, C6?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_4_3 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_4_3 { + .init(lhs, rhs) +} +public struct _Alternation_4_4: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7) { + public typealias Match = (Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_4_4 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_4_4 { + .init(lhs, rhs) +} +public struct _Alternation_4_5: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7, C8) { + public typealias Match = (Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_4_5 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_4_5 { + .init(lhs, rhs) +} +public struct _Alternation_4_6: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3), R1.Match == (W1, C4, C5, C6, C7, C8, C9) { + public typealias Match = (Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_4_6 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_4_6 { + .init(lhs, rhs) +} +public struct _Alternation_5_0: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4) { + public typealias Match = (Substring, C0, C1, C2, C3, C4) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_5_0 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_5_0 { + .init(lhs, rhs) +} +public struct _Alternation_5_1: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_5_1 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_5_1 { + .init(lhs, rhs) +} +public struct _Alternation_5_2: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5?, C6?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_5_2 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_5_2 { + .init(lhs, rhs) +} +public struct _Alternation_5_3: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_5_3 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_5_3 { + .init(lhs, rhs) +} +public struct _Alternation_5_4: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7, C8) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_5_4 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_5_4 { + .init(lhs, rhs) +} +public struct _Alternation_5_5: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4), R1.Match == (W1, C5, C6, C7, C8, C9) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_5_5 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_5_5 { + .init(lhs, rhs) +} +public struct _Alternation_6_0: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_6_0 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_6_0 { + .init(lhs, rhs) +} +public struct _Alternation_6_1: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_6_1 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_6_1 { + .init(lhs, rhs) +} +public struct _Alternation_6_2: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6?, C7?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_6_2 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_6_2 { + .init(lhs, rhs) +} +public struct _Alternation_6_3: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7, C8) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_6_3 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_6_3 { + .init(lhs, rhs) +} +public struct _Alternation_6_4: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5), R1.Match == (W1, C6, C7, C8, C9) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_6_4 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_6_4 { + .init(lhs, rhs) +} +public struct _Alternation_7_0: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_7_0 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_7_0 { + .init(lhs, rhs) +} +public struct _Alternation_7_1: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6, C7?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_7_1 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_7_1 { + .init(lhs, rhs) +} +public struct _Alternation_7_2: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7, C8) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_7_2 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_7_2 { + .init(lhs, rhs) +} +public struct _Alternation_7_3: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6), R1.Match == (W1, C7, C8, C9) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_7_3 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_7_3 { + .init(lhs, rhs) +} +public struct _Alternation_8_0: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6, C7) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_8_0 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_8_0 { + .init(lhs, rhs) +} +public struct _Alternation_8_1: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Match == (W1, C8) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_8_1 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_8_1 { + .init(lhs, rhs) +} +public struct _Alternation_8_2: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.Match == (W1, C8, C9) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?, C9?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_8_2 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_8_2 { + .init(lhs, rhs) +} +public struct _Alternation_9_0: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_9_0 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_9_0 { + .init(lhs, rhs) +} +public struct _Alternation_9_1: RegexProtocol where R0: RegexProtocol, R1: RegexProtocol, R0.Match == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.Match == (W1, C9) { + public typealias Match = (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9?) + public let regex: Regex + + public init(_ left: R0, _ right: R1) { + self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root)) + } +} + +extension AlternationBuilder { + public static func buildBlock(combining next: R1, into combined: R0) -> _Alternation_9_1 { + .init(combined, next) + } +} + +public func | (lhs: R0, rhs: R1) -> _Alternation_9_1 { + .init(lhs, rhs) +} +extension AlternationBuilder { + public static func buildBlock(_ regex: R) -> Regex<(W, C0?)> where R: RegexProtocol, R.Match == (W, C0) { + .init(node: .alternation([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])) + } +} +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])) + } +} +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])) + } +} +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])) + } +} +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])) + } +} +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])) + } +} +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])) + } +} +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])) + } +} // END AUTO-GENERATED CONTENT diff --git a/Sources/_StringProcessing/RegexDSL/Core.swift b/Sources/_StringProcessing/RegexDSL/Core.swift index f161ee227..b426d1565 100644 --- a/Sources/_StringProcessing/RegexDSL/Core.swift +++ b/Sources/_StringProcessing/RegexDSL/Core.swift @@ -130,12 +130,6 @@ extension RegexProtocol { in inputRange: Range, mode: MatchMode = .wholeString ) -> RegexMatch? { - // Casts a Swift tuple to the custom `Tuple`, assuming their memory - // layout is compatible. - func bitCastToMatch(_ x: T) -> Match { - assert(MemoryLayout.size == MemoryLayout.size) - return unsafeBitCast(x, to: Match.self) - } // TODO: Remove this branch when the matching engine supports captures. if regex.hasCapture { let vm = HareVM(program: regex.program.legacyLoweredProgram) @@ -151,7 +145,7 @@ extension RegexProtocol { let typeErasedMatch = captures.matchValue( withWholeMatch: input[range] ) - convertedMatch = _openExistential(typeErasedMatch, do: bitCastToMatch) + convertedMatch = typeErasedMatch as! Match } return RegexMatch(range: range, match: convertedMatch) } diff --git a/Sources/_StringProcessing/RegexDSL/DSL.swift b/Sources/_StringProcessing/RegexDSL/DSL.swift index a2daf579e..392edf225 100644 --- a/Sources/_StringProcessing/RegexDSL/DSL.swift +++ b/Sources/_StringProcessing/RegexDSL/DSL.swift @@ -113,31 +113,42 @@ public func oneOrMore(_ cc: CharacterClass) -> _OneOrMore_0 { // MARK: Alternation -// TODO: Support heterogeneous capture alternation. -public struct Alternation< - Component1: RegexProtocol, Component2: RegexProtocol ->: RegexProtocol { - public typealias Match = Component1.Match +// TODO: Variadic generics +// @resultBuilder +// struct AlternationBuilder { +// @_disfavoredOverload +// func buildBlock(_ regex: R) -> R +// func buildBlock< +// R: RegexProtocol, W0, C0... +// >( +// _ regex: R +// ) -> R where R.Match == (W, C...) +// } - public let regex: Regex +@resultBuilder +public struct AlternationBuilder { + @_disfavoredOverload + public static func buildBlock(_ regex: R) -> R { + regex + } - public init(_ first: Component1, _ second: Component2) { - regex = .init(node: .alternation([ - first.regex.root, second.regex.root - ])) + public static func buildExpression(_ regex: R) -> R { + regex } - public init( - @RegexBuilder _ content: () -> Alternation - ) { - self = content() + public static func buildEither(first component: R) -> R { + component + } + + public static func buildEither(second component: R) -> R { + component } } -public func | ( - lhs: Component1, rhs: Component2 -) -> Alternation { - .init(lhs, rhs) +public func oneOf( + @AlternationBuilder builder: () -> R +) -> R { + builder() } // MARK: - Capture diff --git a/Sources/_StringProcessing/RegexDSL/DSLTree.swift b/Sources/_StringProcessing/RegexDSL/DSLTree.swift index 9ff10a42b..5e79575bb 100644 --- a/Sources/_StringProcessing/RegexDSL/DSLTree.swift +++ b/Sources/_StringProcessing/RegexDSL/DSLTree.swift @@ -493,4 +493,11 @@ extension DSLTree.Node { } return .concatenation([self, newNode]) } + + func appendingAlternationCase(_ newNode: DSLTree.Node) -> DSLTree.Node { + if case .alternation(let components) = self { + return .alternation(components + [newNode]) + } + return .alternation([self, newNode]) + } } diff --git a/Tests/RegexTests/RegexDSLTests.swift b/Tests/RegexTests/RegexDSLTests.swift index 1e803396d..4fa8f7030 100644 --- a/Tests/RegexTests/RegexDSLTests.swift +++ b/Tests/RegexTests/RegexDSLTests.swift @@ -43,6 +43,71 @@ class RegexDSLTests: XCTestCase { XCTAssertTrue(match.match == ("a c", " ", "c")) } + func testAlternation() throws { + do { + let regex = oneOf { + "aaa" + } + XCTAssertTrue("aaa".match(regex)?.match == "aaa") + XCTAssertNil("aab".match(regex)?.match) + } + do { + let regex = oneOf { + "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") + } + do { + let regex = Regex { + "ab" + oneOf { + "c" + "def" + }.capture().+ + } + XCTAssertTrue( + try XCTUnwrap("abc".match(regex)?.match) == ("abc", ["c"])) + } + do { + let regex = oneOf { + "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") + } + do { + let regex = oneOf { + "aaa".capture() + } + XCTAssertTrue( + try XCTUnwrap("aaa".match(regex)?.match) == ("aaa", "aaa")) + XCTAssertNil("aab".match(regex)?.match) + } + do { + let regex = oneOf { + "aaa".capture() + "bbb".capture() + "ccc".capture() + } + XCTAssertTrue( + try XCTUnwrap("aaa".match(regex)?.match) == ("aaa", "aaa", nil, nil)) + XCTAssertTrue( + try XCTUnwrap("bbb".match(regex)?.match) == ("bbb", nil, "bbb", nil)) + XCTAssertTrue( + try XCTUnwrap("ccc".match(regex)?.match) == ("ccc", nil, nil, "ccc")) + XCTAssertNil("aab".match(regex)?.match) + } + } + func testCombinators() throws { let regex = Regex { "a".+ @@ -51,15 +116,20 @@ class RegexDSLTests: XCTestCase { CharacterClass.hexDigit.capture().* // [Substring] "e".? ("t" | "k").capture() // Substring + oneOf { "k".capture(); "j".capture() } // (Substring?, Substring?) } // Assert the inferred capture type. - let _: (Substring, Substring, Substring, [Substring], Substring).Type + let _: (Substring, Substring, Substring, [Substring], Substring, Substring?, Substring?).Type = type(of: regex).Match.self - let maybeMatch = "aaaabccccdddk".match(regex) - let match = try XCTUnwrap(maybeMatch) - XCTAssertTrue( - match.match - == ("aaaabccccdddk", "b", "cccc", ["d", "d", "d"], "k")) + let maybeMatch = "aaaabccccdddkj".match(regex) + let match = try XCTUnwrap(maybeMatch).match + XCTAssertEqual(match.0, "aaaabccccdddkj") + XCTAssertEqual(match.1, "b") + XCTAssertEqual(match.2, "cccc") + XCTAssertEqual(match.3, ["d", "d", "d"]) + XCTAssertEqual(match.4, "k") + XCTAssertEqual(match.5, .none) + XCTAssertEqual(match.6, .some("j")) } func testNestedGroups() throws {