From 65f62ed5614abf1846b98f45698db3c57f92c5f0 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 18 May 2022 12:28:04 -0500 Subject: [PATCH 1/3] Add a primary associated type to RegexComponent --- Sources/_StringProcessing/Regex/Core.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index 5d2101afe..5c99e2ccd 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -14,7 +14,7 @@ /// A type that represents a regular expression. @available(SwiftStdlib 5.7, *) -public protocol RegexComponent { +public protocol RegexComponent { associatedtype RegexOutput var regex: Regex { get } } From f80763e6d13e46e54ffb9a12b75f1b7069250a38 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 18 May 2022 12:28:18 -0500 Subject: [PATCH 2/3] Switch algorithms methods to using opaque params --- .../Algorithms/Algorithms/Contains.swift | 2 +- .../Algorithms/Algorithms/FirstRange.swift | 2 +- .../Algorithms/Algorithms/Ranges.swift | 4 ++-- .../Algorithms/Algorithms/Replace.swift | 12 ++++++------ .../Algorithms/Algorithms/Split.swift | 4 ++-- .../Algorithms/Algorithms/StartsWith.swift | 2 +- .../Algorithms/Algorithms/Trim.swift | 4 ++-- .../Algorithms/Matching/FirstMatch.swift | 6 +++--- .../Algorithms/Matching/MatchReplace.swift | 18 +++++++++--------- .../Algorithms/Matching/Matches.swift | 8 ++++---- 10 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift index bb86f4676..b3d79b945 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift @@ -69,7 +69,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: `true` if the regex was found in the collection, otherwise /// `false`. @available(SwiftStdlib 5.7, *) - public func contains(_ regex: R) -> Bool { + public func contains(_ regex: some RegexComponent) -> Bool { _contains(RegexConsumer(regex)) } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index ad5c535d4..e295405d7 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -76,7 +76,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A range in the collection of the first occurrence of `regex`. /// Returns `nil` if `regex` is not found. @available(SwiftStdlib 5.7, *) - public func firstRange(of regex: R) -> Range? { + public func firstRange(of regex: some RegexComponent) -> Range? { _firstRange(of: RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift index 9f3c50c7c..114150661 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift @@ -252,8 +252,8 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A collection or ranges in the receiver of all occurrences of /// `regex`. Returns an empty collection if `regex` is not found. @available(SwiftStdlib 5.7, *) - public func ranges( - of regex: R + public func ranges( + of regex: some RegexComponent ) -> [Range] { Array(_ranges(of: regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift index daf726fe7..9c5b3cb3e 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift @@ -188,8 +188,8 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` in `subrange` are replaced by `replacement`. @available(SwiftStdlib 5.7, *) - public func replacing( - _ regex: R, + public func replacing( + _ regex: some RegexComponent, with replacement: Replacement, subrange: Range, maxReplacements: Int = .max @@ -211,8 +211,8 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. @available(SwiftStdlib 5.7, *) - public func replacing( - _ regex: R, + public func replacing( + _ regex: some RegexComponent, with replacement: Replacement, maxReplacements: Int = .max ) -> Self where Replacement.Element == Element { @@ -231,8 +231,8 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. @available(SwiftStdlib 5.7, *) - public mutating func replace( - _ regex: R, + public mutating func replace( + _ regex: some RegexComponent, with replacement: Replacement, maxReplacements: Int = .max ) where Replacement.Element == Element { diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index 412197557..7aa113d8f 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -383,8 +383,8 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A collection of substrings, split from this collection's /// elements. @_disfavoredOverload - public func split( - separator: R, + public func split( + separator: some RegexComponent, maxSplits: Int = .max, omittingEmptySubsequences: Bool = true ) -> [SubSequence] { diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift index c8aaf9126..694651f3a 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift @@ -55,7 +55,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: A regex to compare to this sequence. /// - Returns: `true` if the initial elements of the sequence matches the /// beginning of `regex`; otherwise, `false`. - public func starts(with regex: R) -> Bool { + public func starts(with regex: some RegexComponent) -> Bool { _starts(with: RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index 2e955507b..ea994e094 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -291,7 +291,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A collection containing the elements that does not match /// `prefix` from the start. @available(SwiftStdlib 5.7, *) - public func trimmingPrefix(_ regex: R) -> SubSequence { + public func trimmingPrefix(_ regex: some RegexComponent) -> SubSequence { _trimmingPrefix(RegexConsumer(regex)) } @@ -312,7 +312,7 @@ extension RangeReplaceableCollection /// Removes the initial elements that matches the given regex. /// - Parameter regex: The regex to remove from this collection. @available(SwiftStdlib 5.7, *) - public mutating func trimPrefix(_ regex: R) { + public mutating func trimPrefix(_ regex: some RegexComponent) { _trimPrefix(RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index 2b6dd1704..c8c6867f4 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -58,9 +58,9 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: The first match of `regex` in the collection, or `nil` if /// there isn't a match. @available(SwiftStdlib 5.7, *) - public func firstMatch( - of r: R - ) -> Regex.Match? { + public func firstMatch( + of r: some RegexComponent + ) -> Regex.Match? { let slice = self[...] return try? r.regex.firstMatch(in: slice) } diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index 38224e30f..6bc9b4d77 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -126,11 +126,11 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. @available(SwiftStdlib 5.7, *) - public func replacing( - _ regex: R, + public func replacing( + _ regex: some RegexComponent, subrange: Range, maxReplacements: Int = .max, - with replacement: (Regex.Match) throws -> Replacement + with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element { precondition(maxReplacements >= 0) @@ -162,10 +162,10 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. @available(SwiftStdlib 5.7, *) - public func replacing( - _ regex: R, + public func replacing( + _ regex: some RegexComponent, maxReplacements: Int = .max, - with replacement: (Regex.Match) throws -> Replacement + with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element { try replacing( regex, @@ -183,10 +183,10 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - replacement: A closure that receives the full match information, /// including captures, and returns a replacement collection. @available(SwiftStdlib 5.7, *) - public mutating func replace( - _ regex: R, + public mutating func replace( + _ regex: some RegexComponent, maxReplacements: Int = .max, - with replacement: (Regex.Match) throws -> Replacement + with replacement: (Regex.Match) throws -> Replacement ) rethrows where Replacement.Element == Element { self = try replacing( regex, diff --git a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift index 293520735..a7cd17779 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift @@ -204,15 +204,15 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: The regex to search for. /// - Returns: A collection of matches of `regex`. @available(SwiftStdlib 5.7, *) - public func matches( - of r: R - ) -> [Regex.Match] { + public func matches( + of r: some RegexComponent + ) -> [Regex.Match] { let slice = self[...] var start = self.startIndex let end = self.endIndex let regex = r.regex - var result = [Regex.Match]() + var result = [Regex.Match]() while start <= end { guard let match = try? regex._firstMatch( slice.base, in: start.. Date: Wed, 18 May 2022 12:33:07 -0500 Subject: [PATCH 3/3] Use primary assoc type in RegexBuilder algorithms --- Sources/RegexBuilder/Algorithms.swift | 82 +++++++++++++-------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/Sources/RegexBuilder/Algorithms.swift b/Sources/RegexBuilder/Algorithms.swift index f1f6d97a0..2660c7892 100644 --- a/Sources/RegexBuilder/Algorithms.swift +++ b/Sources/RegexBuilder/Algorithms.swift @@ -23,9 +23,9 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter content: A closure that returns a regex to match against. /// - Returns: The match if there is one, or `nil` if none. @available(SwiftStdlib 5.7, *) - public func wholeMatch( - @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { + public func wholeMatch( + @RegexComponentBuilder of content: () -> some RegexComponent + ) -> Regex.Match? { wholeMatch(of: content()) } @@ -35,9 +35,9 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter content: A closure that returns a regex to match against. /// - Returns: The match if there is one, or `nil` if none. @available(SwiftStdlib 5.7, *) - public func prefixMatch( - @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { + public func prefixMatch( + @RegexComponentBuilder of content: () -> some RegexComponent + ) -> Regex.Match? { prefixMatch(of: content()) } @@ -49,8 +49,8 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: `true` if the regex returned by `content` matched anywhere in /// this collection, otherwise `false`. @available(SwiftStdlib 5.7, *) - public func contains( - @RegexComponentBuilder _ content: () -> R + public func contains( + @RegexComponentBuilder _ content: () -> some RegexComponent ) -> Bool { contains(content()) } @@ -63,8 +63,8 @@ extension BidirectionalCollection where SubSequence == Substring { /// match of if the regex returned by `content`. Returns `nil` if no match /// for the regex is found. @available(SwiftStdlib 5.7, *) - public func firstRange( - @RegexComponentBuilder of content: () -> R + public func firstRange( + @RegexComponentBuilder of content: () -> some RegexComponent ) -> Range? { firstRange(of: content()) } @@ -78,8 +78,8 @@ extension BidirectionalCollection where SubSequence == Substring { /// `content`. Returns an empty collection if no match for the regex /// is found. @available(SwiftStdlib 5.7, *) - public func ranges( - @RegexComponentBuilder of content: () -> R + public func ranges( + @RegexComponentBuilder of content: () -> some RegexComponent ) -> [Range] { ranges(of: content()) } @@ -99,10 +99,10 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A collection of substrings, split from this collection's /// elements. @available(SwiftStdlib 5.7, *) - public func split( + public func split( maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true, - @RegexComponentBuilder separator: () -> R + @RegexComponentBuilder separator: () -> some RegexComponent ) -> [SubSequence] { split(separator: separator(), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) } @@ -115,8 +115,8 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: `true` if the initial elements of this collection match /// regex returned by `content`; otherwise, `false`. @available(SwiftStdlib 5.7, *) - public func starts( - @RegexComponentBuilder with content: () -> R + public func starts( + @RegexComponentBuilder with content: () -> some RegexComponent ) -> Bool { starts(with: content()) } @@ -132,8 +132,8 @@ extension BidirectionalCollection where SubSequence == Substring { /// the start of the collection, the entire contents of this collection /// are returned. @available(SwiftStdlib 5.7, *) - public func trimmingPrefix( - @RegexComponentBuilder _ content: () -> R + public func trimmingPrefix( + @RegexComponentBuilder _ content: () -> some RegexComponent ) -> SubSequence { trimmingPrefix(content()) } @@ -145,9 +145,9 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: The first match for the regex created by `content` in this /// collection, or `nil` if no match is found. @available(SwiftStdlib 5.7, *) - public func firstMatch( - @RegexComponentBuilder of content: () -> R - ) -> Regex.Match? { + public func firstMatch( + @RegexComponentBuilder of content: () -> some RegexComponent + ) -> Regex.Match? { firstMatch(of: content()) } @@ -159,9 +159,9 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: A collection of matches for the regex returned by `content`. /// If no matches are found, the returned collection is empty. @available(SwiftStdlib 5.7, *) - public func matches( - @RegexComponentBuilder of content: () -> R - ) -> [Regex.Match] { + public func matches( + @RegexComponentBuilder of content: () -> some RegexComponent + ) -> [Regex.Match] { matches(of: content()) } } @@ -175,8 +175,8 @@ where Self: BidirectionalCollection, SubSequence == Substring { /// - Parameter content: A closure that returns the regex to search for /// at the start of this collection. @available(SwiftStdlib 5.7, *) - public mutating func trimPrefix( - @RegexComponentBuilder _ content: () -> R + public mutating func trimPrefix( + @RegexComponentBuilder _ content: () -> some RegexComponent ) { trimPrefix(content()) } @@ -196,11 +196,11 @@ where Self: BidirectionalCollection, SubSequence == Substring { /// - Returns: A new collection in which all matches for regex in `subrange` /// are replaced by `replacement`, using `content` to create the regex. @available(SwiftStdlib 5.7, *) - public func replacing( + public func replacing( with replacement: Replacement, subrange: Range, maxReplacements: Int = .max, - @RegexComponentBuilder content: () -> R + @RegexComponentBuilder content: () -> some RegexComponent ) -> Self where Replacement.Element == Element { replacing(content(), with: replacement, subrange: subrange, maxReplacements: maxReplacements) } @@ -218,10 +218,10 @@ where Self: BidirectionalCollection, SubSequence == Substring { /// - Returns: A new collection in which all matches for regex in `subrange` /// are replaced by `replacement`, using `content` to create the regex. @available(SwiftStdlib 5.7, *) - public func replacing( + public func replacing( with replacement: Replacement, maxReplacements: Int = .max, - @RegexComponentBuilder content: () -> R + @RegexComponentBuilder content: () -> some RegexComponent ) -> Self where Replacement.Element == Element { replacing(content(), with: replacement, maxReplacements: maxReplacements) } @@ -237,10 +237,10 @@ where Self: BidirectionalCollection, SubSequence == Substring { /// - content: A closure that returns the collection to search for /// and replace. @available(SwiftStdlib 5.7, *) - public mutating func replace( + public mutating func replace( with replacement: Replacement, maxReplacements: Int = .max, - @RegexComponentBuilder content: () -> R + @RegexComponentBuilder content: () -> some RegexComponent ) where Replacement.Element == Element { replace(content(), with: replacement, maxReplacements: maxReplacements) } @@ -262,11 +262,11 @@ where Self: BidirectionalCollection, SubSequence == Substring { /// are replaced by the result of calling `replacement`, where regex /// is the result of calling `content`. @available(SwiftStdlib 5.7, *) - public func replacing( + public func replacing( subrange: Range, maxReplacements: Int = .max, - @RegexComponentBuilder content: () -> R, - with replacement: (Regex.Match) throws -> Replacement + @RegexComponentBuilder content: () -> some RegexComponent, + with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element { try replacing(content(), subrange: subrange, maxReplacements: maxReplacements, with: replacement) } @@ -286,10 +286,10 @@ where Self: BidirectionalCollection, SubSequence == Substring { /// are replaced by the result of calling `replacement`, where regex is /// the result of calling `content`. @available(SwiftStdlib 5.7, *) - public func replacing( + public func replacing( maxReplacements: Int = .max, - @RegexComponentBuilder content: () -> R, - with replacement: (Regex.Match) throws -> Replacement + @RegexComponentBuilder content: () -> some RegexComponent, + with replacement: (Regex.Match) throws -> Replacement ) rethrows -> Self where Replacement.Element == Element { try replacing(content(), maxReplacements: maxReplacements, with: replacement) } @@ -305,10 +305,10 @@ where Self: BidirectionalCollection, SubSequence == Substring { /// - replacement: A closure that receives the full match information, /// including captures, and returns a replacement collection. @available(SwiftStdlib 5.7, *) - public mutating func replace( + public mutating func replace( maxReplacements: Int = .max, - @RegexComponentBuilder content: () -> R, - with replacement: (Regex.Match) throws -> Replacement + @RegexComponentBuilder content: () -> some RegexComponent, + with replacement: (Regex.Match) throws -> Replacement ) rethrows where Replacement.Element == Element { try replace(content(), maxReplacements: maxReplacements, with: replacement) }