diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index 30fc11598..75c06a0bf 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -211,19 +211,14 @@ struct VariadicsGenerator: ParsableCommand { } func emitConcatenation(leftArity: Int, rightArity: Int) { - func genericParameters(withConstraints: Bool) -> String { + let genericParams: String = { var result = "W0, W1" result += (0..( - combining next: R1, into combined: R0 - ) -> \(regexTypeName)<\(matchType)> \(whereClause) { - .init(node: combined.regex.root.appending(next.regex.root)) - } + @_disfavoredOverload + public static func buildBlock<\(genericParams)>( + combining next: R1, into combined: R0 + ) -> \(regexTypeName)<\(matchType)> \(whereClause) { + .init(node: combined.regex.root.appending(next.regex.root)) } + } """) } @@ -338,19 +333,16 @@ struct VariadicsGenerator: ParsableCommand { func emitQuantifier(kind: QuantifierKind, arity: Int) { assert(arity >= 0) - func genericParameters(withConstraints: Bool) -> String { + let genericParams: String = { var result = "" if arity > 0 { result += "W" result += (0..( - _ component: Component + public func \(kind.rawValue)<\(genericParams)>( + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> \(regexTypeName)<\(matchType)> \(whereClause) { - .init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component.regex.root)) + .init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component.regex.root)) } \(arity == 0 ? "@_disfavoredOverload" : "") - public func \(kind.rawValue)<\(genericParameters(withConstraints: true))>( + public func \(kind.rawValue)<\(genericParams)>( + _ behavior: QuantificationBehavior = .eagerly, @RegexBuilder _ component: () -> Component ) -> \(regexTypeName)<\(matchType)> \(whereClause) { - .init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component().regex.root)) + .init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component().regex.root)) } \(arity == 0 ? "@_disfavoredOverload" : "") - public postfix func \(kind.operatorName)<\(genericParameters(withConstraints: true))>( + public postfix func \(kind.operatorName)<\(genericParams)>( _ component: Component ) -> \(regexTypeName)<\(matchType)> \(whereClause) { .init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component.regex.root)) @@ -389,7 +383,7 @@ struct VariadicsGenerator: ParsableCommand { \(kind == .zeroOrOne ? """ extension RegexBuilder { - public static func buildLimitedAvailability<\(genericParameters(withConstraints: true))>( + public static func buildLimitedAvailability<\(genericParams)>( _ component: Component ) -> \(regexTypeName)<\(matchType)> \(whereClause) { .init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component.regex.root)) diff --git a/Sources/_StringProcessing/RegexDSL/DSL.swift b/Sources/_StringProcessing/RegexDSL/DSL.swift index 33869b56a..d1e7d42bf 100644 --- a/Sources/_StringProcessing/RegexDSL/DSL.swift +++ b/Sources/_StringProcessing/RegexDSL/DSL.swift @@ -62,6 +62,44 @@ extension CharacterClass: RegexProtocol { // Note: Quantifiers are currently gyb'd. +/// Specifies how much to attempt to match when using a quantifier. +public struct QuantificationBehavior { + internal enum Kind { + case eagerly + case reluctantly + case possessively + } + + var kind: Kind + + internal var astKind: AST.Quantification.Kind { + switch kind { + case .eagerly: return .eager + case .reluctantly: return .reluctant + case .possessively: return .possessive + } + } +} + +extension QuantificationBehavior { + /// Match as much of the input string as possible, backtracking when + /// necessary. + public static var eagerly: QuantificationBehavior { + .init(kind: .eagerly) + } + + /// Match as little of the input string as possible, expanding the matched + /// region as necessary to complete a match. + public static var reluctantly: QuantificationBehavior { + .init(kind: .reluctantly) + } + + /// Match as much of the input string as possible, performing no backtracking. + public static var possessively: QuantificationBehavior { + .init(kind: .possessively) + } +} + // TODO: Variadic generics // struct _OneOrMore // where R.Match == (W, C...) @@ -99,16 +137,25 @@ postfix operator .* postfix operator .+ // Overloads for quantifying over a character class. -public func zeroOrOne(_ cc: CharacterClass) -> Regex { - .init(node: .quantification(.zeroOrOne, .eager, cc.regex.root)) +public func zeroOrOne( + _ cc: CharacterClass, + _ behavior: QuantificationBehavior = .eagerly +) -> Regex { + .init(node: .quantification(.zeroOrOne, behavior.astKind, cc.regex.root)) } -public func many(_ cc: CharacterClass) -> Regex { - .init(node: .quantification(.zeroOrMore, .eager, cc.regex.root)) +public func many( + _ cc: CharacterClass, + _ behavior: QuantificationBehavior = .eagerly +) -> Regex { + .init(node: .quantification(.zeroOrMore, behavior.astKind, cc.regex.root)) } -public func oneOrMore(_ cc: CharacterClass) -> Regex { - .init(node: .quantification(.oneOrMore, .eager, cc.regex.root)) +public func oneOrMore( + _ cc: CharacterClass, + _ behavior: QuantificationBehavior = .eagerly +) -> Regex { + .init(node: .quantification(.oneOrMore, behavior.astKind, cc.regex.root)) } // MARK: Alternation diff --git a/Sources/_StringProcessing/RegexDSL/Variadics.swift b/Sources/_StringProcessing/RegexDSL/Variadics.swift index d73b9f043..8193251ee 100644 --- a/Sources/_StringProcessing/RegexDSL/Variadics.swift +++ b/Sources/_StringProcessing/RegexDSL/Variadics.swift @@ -77,445 +77,445 @@ extension RegexBuilder { } } extension RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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 RegexBuilder { + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { - @_disfavoredOverload - 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)) - } + @_disfavoredOverload + 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 RegexBuilder { @_disfavoredOverload public static func buildBlock( @@ -600,16 +600,18 @@ extension RegexBuilder { @_disfavoredOverload public func optionally( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) } @_disfavoredOverload public func optionally( + _ behavior: QuantificationBehavior = .eagerly, @RegexBuilder _ component: () -> Component ) -> Regex { - .init(node: .quantification(.zeroOrOne, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } @_disfavoredOverload @@ -628,16 +630,18 @@ extension RegexBuilder { } @_disfavoredOverload public func many( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex { - .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } @_disfavoredOverload public func many( + _ behavior: QuantificationBehavior = .eagerly, @RegexBuilder _ component: () -> Component ) -> Regex { - .init(node: .quantification(.zeroOrMore, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } @_disfavoredOverload @@ -650,16 +654,18 @@ public postfix func .+( @_disfavoredOverload public func oneOrMore( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex { - .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) } @_disfavoredOverload public func oneOrMore( + _ behavior: QuantificationBehavior = .eagerly, @RegexBuilder _ component: () -> Component ) -> Regex { - .init(node: .quantification(.oneOrMore, .eager, component().regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } @_disfavoredOverload @@ -672,16 +678,18 @@ public postfix func .*( public func optionally( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, C0?)> where Component.Match == (W, C0) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } @@ -700,16 +708,18 @@ extension RegexBuilder { } public func many( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, [C0])> where Component.Match == (W, C0) { - .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } public func many( + _ behavior: QuantificationBehavior = .eagerly, @RegexBuilder _ component: () -> Component ) -> Regex<(Substring, [C0])> where Component.Match == (W, C0) { - .init(node: .quantification(.zeroOrMore, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } @@ -722,16 +732,18 @@ public postfix func .+( public func oneOrMore( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, [C0])> where Component.Match == (W, C0) { - .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } @@ -744,16 +756,18 @@ public postfix func .*( public func optionally( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, (C0, C1)?)> where Component.Match == (W, C0, C1) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } @@ -772,16 +786,18 @@ extension RegexBuilder { } public func many( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, [(C0, C1)])> where Component.Match == (W, C0, C1) { - .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } public func many( + _ behavior: QuantificationBehavior = .eagerly, @RegexBuilder _ component: () -> Component ) -> Regex<(Substring, [(C0, C1)])> where Component.Match == (W, C0, C1) { - .init(node: .quantification(.zeroOrMore, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } @@ -794,16 +810,18 @@ public postfix func .+( public func oneOrMore( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, [(C0, C1)])> where Component.Match == (W, C0, C1) { - .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } @@ -816,16 +834,18 @@ public postfix func .*( public func optionally( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, (C0, C1, C2)?)> where Component.Match == (W, C0, C1, C2) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } @@ -844,16 +864,18 @@ extension RegexBuilder { } public func many( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, [(C0, C1, C2)])> where Component.Match == (W, C0, C1, C2) { - .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } public func many( + _ behavior: QuantificationBehavior = .eagerly, @RegexBuilder _ component: () -> Component ) -> Regex<(Substring, [(C0, C1, C2)])> where Component.Match == (W, C0, C1, C2) { - .init(node: .quantification(.zeroOrMore, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } @@ -866,16 +888,18 @@ public postfix func .+( public func oneOrMore( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, [(C0, C1, C2)])> where Component.Match == (W, C0, C1, C2) { - .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } @@ -888,16 +912,18 @@ public postfix func .*( public func optionally( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, (C0, C1, C2, C3)?)> where Component.Match == (W, C0, C1, C2, C3) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } @@ -916,16 +942,18 @@ extension RegexBuilder { } public func many( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, [(C0, C1, C2, C3)])> where Component.Match == (W, C0, C1, C2, C3) { - .init(node: .quantification(.zeroOrMore, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } public func many( + _ behavior: QuantificationBehavior = .eagerly, @RegexBuilder _ component: () -> Component ) -> Regex<(Substring, [(C0, C1, C2, C3)])> where Component.Match == (W, C0, C1, C2, C3) { - .init(node: .quantification(.zeroOrMore, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } @@ -938,16 +966,18 @@ public postfix func .+( public func oneOrMore( - _ component: Component + _ component: Component, + _ behavior: QuantificationBehavior = .eagerly ) -> Regex<(Substring, [(C0, C1, C2, C3)])> where Component.Match == (W, C0, C1, C2, C3) { - .init(node: .quantification(.oneOrMore, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } @@ -960,16 +990,18 @@ public postfix func .*( public func optionally( - _ component: Component + _ 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, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } @@ -988,16 +1020,18 @@ extension RegexBuilder { } public func many( - _ component: Component + _ 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, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } public func many( + _ 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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } @@ -1010,16 +1044,18 @@ public postfix func .+( public func oneOrMore( - _ component: Component + _ 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, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } @@ -1032,16 +1068,18 @@ public postfix func .*( public func optionally( - _ component: Component + _ 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, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } @@ -1060,16 +1098,18 @@ extension RegexBuilder { } public func many( - _ component: Component + _ 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, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } public func many( + _ 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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } @@ -1082,16 +1122,18 @@ public postfix func .+( public func oneOrMore( - _ component: Component + _ 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, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } @@ -1104,16 +1146,18 @@ public postfix func .*( public func optionally( - _ component: Component + _ 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, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } @@ -1132,16 +1176,18 @@ extension RegexBuilder { } public func many( - _ component: Component + _ 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, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } public func many( + _ 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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } @@ -1154,16 +1200,18 @@ public postfix func .+( public func oneOrMore( - _ component: Component + _ 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, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } @@ -1176,16 +1224,18 @@ public postfix func .*( public func optionally( - _ component: Component + _ 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, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } @@ -1204,16 +1254,18 @@ extension RegexBuilder { } public func many( - _ component: Component + _ 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, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } public func many( + _ 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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } @@ -1226,16 +1278,18 @@ public postfix func .+( - _ component: Component + _ 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, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } @@ -1248,16 +1302,18 @@ public postfix func .*( - _ component: Component + _ 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, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) } @@ -1276,16 +1332,18 @@ extension RegexBuilder { } public func many( - _ component: Component + _ 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, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) } public func many( + _ 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, .eager, component().regex.root)) + .init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) } @@ -1298,16 +1356,18 @@ public postfix func .+( - _ component: Component + _ 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, .eager, component.regex.root)) + .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, .eager, component().regex.root)) + .init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) } diff --git a/Tests/RegexTests/RegexDSLTests.swift b/Tests/RegexTests/RegexDSLTests.swift index 3dd660187..aa7b89d32 100644 --- a/Tests/RegexTests/RegexDSLTests.swift +++ b/Tests/RegexTests/RegexDSLTests.swift @@ -13,6 +13,30 @@ import XCTest @testable import _StringProcessing class RegexDSLTests: XCTestCase { + func _testDSLCaptures( + _ tests: (input: String, expectedCaptures: CaptureType?)..., + captureType: CaptureType.Type, + _ equivalence: (CaptureType, CaptureType) -> Bool, + file: StaticString = #file, + line: UInt = #line, + @RegexBuilder _ 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( + equivalence(captures, expectedCaptures), + "'\(captures)' is not equal to the expected '\(expectedCaptures)'.", + file: file, line: line) + } else { + XCTAssertNil(maybeMatch, file: file, line: line) + } + } + } + func testSimpleStrings() throws { let regex = Regex { "a" @@ -31,16 +55,14 @@ class RegexDSLTests: XCTestCase { } func testCharacterClasses() throws { - let regex = Regex { + try _testDSLCaptures( + ("a c", ("a c", " ", "c")), + captureType: (Substring, Substring, Substring).self, ==) + { CharacterClass.any - capture(CharacterClass.whitespace) // Character + capture(CharacterClass.whitespace) // Substring capture("c") // Substring } - // Assert the inferred capture type. - let _: (Substring, Substring, Substring).Type = type(of: regex).Match.self - let maybeMatch = "a c".match(regex) - let match = try XCTUnwrap(maybeMatch) - XCTAssertTrue(match.match == ("a c", " ", "c")) } func testAlternation() throws { @@ -111,7 +133,10 @@ class RegexDSLTests: XCTestCase { } func testCombinators() throws { - let regex = Regex { + try _testDSLCaptures( + ("aaaabccccdddkj", ("aaaabccccdddkj", "b", "cccc", ["d", "d", "d"], "k", nil, "j")), + captureType: (Substring, Substring, Substring, [Substring], Substring, Substring?, Substring?).self, ==) + { "a".+ capture(oneOrMore(Character("b"))) // Substring capture(many("c")) // Substring @@ -120,22 +145,47 @@ class RegexDSLTests: XCTestCase { capture("t" | "k") // Substring oneOf { capture("k"); capture("j") } // (Substring?, Substring?) } - // Assert the inferred capture type. - let _: (Substring, Substring, Substring, [Substring], Substring, Substring?, Substring?).Type - = type(of: regex).Match.self - 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 testQuantificationBehavior() throws { + try _testDSLCaptures( + ("abc1def2", ("abc1def2", ["2"])), + captureType: (Substring, [Substring]).self, ==) + { + oneOrMore { + oneOrMore(.word) + capture(CharacterClass.digit) + } + } + + try _testDSLCaptures( + ("abc1def2", ("abc1def2", ["1", "2"])), + captureType: (Substring, [Substring]).self, ==) + { + oneOrMore { + oneOrMore(.word, .reluctantly) + capture(CharacterClass.digit) + } + } + + try _testDSLCaptures( + ("abc1def2", ("abc1def2", ["1", "2"])), + captureType: (Substring, [Substring]).self, ==) + { + oneOrMore { + oneOrMore(.reluctantly) { + CharacterClass.word + } + capture(CharacterClass.digit) + } + } } func testNestedGroups() throws { - let regex = Regex { + try _testDSLCaptures( + ("aaaabccccddd", ("aaaabccccddd", [("b", "cccc", ["d", "d", "d"])])), + captureType: (Substring, [(Substring, Substring, [Substring])]).self, ==) + { "a".+ oneOrMore { capture(oneOrMore("b")) @@ -144,16 +194,6 @@ class RegexDSLTests: XCTestCase { "e".? } } - // Assert the inferred capture type. - let _: (Substring, [(Substring, Substring, [Substring])]).Type - = type(of: regex).Match.self - let maybeMatch = "aaaabccccddd".match(regex) - let match = try XCTUnwrap(maybeMatch) - XCTAssertEqual(match.match.1.count, 1) - XCTAssertEqual(match.match.0, "aaaabccccddd") - XCTAssertTrue( - match.match.1[0] - == ("b", "cccc", ["d", "d", "d"])) } func testCapturelessQuantification() throws { @@ -186,7 +226,11 @@ class RegexDSLTests: XCTestCase { } } } - let regex = Regex { + try _testDSLCaptures( + ("aaa 123 apple orange apple", ("aaa 123 apple orange apple", 123, [.apple, .orange, .apple])), + ("aaa ", ("aaa ", nil, [])), + captureType: (Substring, Int?, [Word]).self, ==) + { "a".+ oneOrMore(.whitespace) optionally { @@ -197,24 +241,6 @@ class RegexDSLTests: XCTestCase { capture(oneOrMore(.word)) { Word($0)! } } } - // Assert the inferred capture type. - let _: (Substring, Int?, [Word]).Type = type(of: regex).Match.self - do { - let input = "aaa 123 apple orange apple" - let match = input.match(regex)?.match - let (whole, number, words) = try XCTUnwrap(match) - XCTAssertTrue(whole == input) - XCTAssertEqual(number, 123) - XCTAssertEqual(words, [.apple, .orange, .apple]) - } - do { - let input = "aaa " - let match = input.match(regex)?.match - let (whole, number, words) = try XCTUnwrap(match) - XCTAssertTrue(whole == input) - XCTAssertEqual(number, nil) - XCTAssertTrue(words.isEmpty) - } } func testNestedCaptureTypes() throws { @@ -428,3 +454,18 @@ extension Unicode.Scalar { self = scalar } } + +// MARK: Extra == functions + +// (Substring, [(Substring, Substring, [Substring])]) +typealias S_AS = (Substring, [(Substring, Substring, [Substring])]) + +func ==(lhs: S_AS, rhs: S_AS) -> Bool { + lhs.0 == rhs.0 && lhs.1.elementsEqual(rhs.1, by: ==) +} + +func == ( + l: (T0, T1, T2, T3, T4, T5, T6), r: (T0, T1, T2, T3, T4, T5, T6) +) -> Bool { + l.0 == r.0 && (l.1, l.2, l.3, l.4, l.5, l.6) == (r.1, r.2, r.3, r.4, r.5, r.6) +}