From 0b38ca9bd127bff31ec67a9fa2b60f4d1a23c831 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 6 Oct 2022 17:25:13 -0500 Subject: [PATCH 01/34] Atomically load the lowered program (#610) Since we're atomically initializing the compiled program in `Regex.Program`, we need to pair that with an atomic load. Resolves #609. --- Sources/_StringProcessing/Regex/Core.swift | 27 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index f58f63de7..ba40f4f90 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -95,12 +95,29 @@ extension Regex { /// The program for execution with the matching engine. var loweredProgram: MEProgram { - if let loweredObject = _loweredProgramStorage as? ProgramBox { - return loweredObject.value + /// Atomically loads the compiled program if it has already been stored. + func loadProgram() -> MEProgram? { + guard let loweredObject = _stdlib_atomicLoadARCRef(object: &_loweredProgramStorage) + else { return nil } + return unsafeDowncast(loweredObject, to: ProgramBox.self).value } - let lowered = try! Compiler(tree: tree, compileOptions: compileOptions).emit() - _stdlib_atomicInitializeARCRef(object: &_loweredProgramStorage, desired: ProgramBox(lowered)) - return lowered + + // Use the previously compiled program, if available. + if let program = loadProgram() { + return program + } + + // Compile the DSLTree into a lowered program and store it atomically. + let compiledProgram = try! Compiler(tree: tree, compileOptions: compileOptions).emit() + let storedNewProgram = _stdlib_atomicInitializeARCRef( + object: &_loweredProgramStorage, + desired: ProgramBox(compiledProgram)) + + // Return the winner of the storage race. We're guaranteed at this point + // to have compiled program stored in `_loweredProgramStorage`. + return storedNewProgram + ? compiledProgram + : loadProgram()! } init(ast: AST) { From 335a0c23aeb755fbdbc5a0a32c726f6daf35f303 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 2 Dec 2022 09:22:07 -0600 Subject: [PATCH 02/34] Add tests for line start/end word boundary diffs (#616) The `default` and `simple` word boundaries have different behaviors at the start and end of strings/lines. These tests validate that we have the correct behavior implemented. Related to issue #613. --- Tests/RegexTests/MatchTests.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index 2fa9b9381..a1bf0e76f 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -1517,6 +1517,19 @@ extension RegexTests { (" 123", "23"), ("123 456", "23")) + let defaultBoundaryRegex = try Regex(#"\b.{3}X.{3}\b"#) + // Default word boundaries match at the start/end of a string/line. + XCTAssertNotNil(try defaultBoundaryRegex.firstMatch(in: "---X---")) + XCTAssertNotNil(try defaultBoundaryRegex.firstMatch(in: "abc\n---X---\ndef")) + + let simpleBoundaryRegex = defaultBoundaryRegex.wordBoundaryKind(.simple) + // Simple word boundaries match only when the adjacent position matches \w. + XCTAssertNil(try simpleBoundaryRegex.firstMatch(in: "---X---")) + XCTAssertNil(try simpleBoundaryRegex.firstMatch(in: "abc\n---X---\ndef")) + + XCTAssertNotNil(try simpleBoundaryRegex.firstMatch(in: "x--X--x")) + XCTAssertNotNil(try simpleBoundaryRegex.firstMatch(in: "abc\nx--X--x\ndef")) + // \G and \K let regex = try Regex(#"\Gab"#, as: Substring.self) XCTAssertEqual("abab".matches(of: regex).map(\.output), ["ab", "ab"]) From 54ff5161d4178f92a1701837b5827ac2f521e2da Mon Sep 17 00:00:00 2001 From: Butta Date: Mon, 5 Dec 2022 21:34:37 +0530 Subject: [PATCH 03/34] Add tweaks for Android --- Sources/TestSupport/TestSupport.swift | 2 +- Sources/VariadicsGenerator/VariadicsGenerator.swift | 2 +- Tests/RegexTests/UTS18Tests.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/TestSupport/TestSupport.swift b/Sources/TestSupport/TestSupport.swift index b60adb63f..b562f9255 100644 --- a/Sources/TestSupport/TestSupport.swift +++ b/Sources/TestSupport/TestSupport.swift @@ -15,7 +15,7 @@ import XCTest // *without* `-disable-availability-checking` to ensure the #available check is // not compiled into a no-op. -#if os(Linux) +#if os(Linux) || os(Android) public func XCTExpectFailure( _ message: String? = nil, body: () throws -> Void ) rethrows {} diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index 8ddaee145..ecfc31965 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -14,7 +14,7 @@ import ArgumentParser #if os(macOS) import Darwin -#elseif os(Linux) +#elseif canImport(Glibc) import Glibc #elseif os(Windows) import CRT diff --git a/Tests/RegexTests/UTS18Tests.swift b/Tests/RegexTests/UTS18Tests.swift index 11479bfb6..4cf68a153 100644 --- a/Tests/RegexTests/UTS18Tests.swift +++ b/Tests/RegexTests/UTS18Tests.swift @@ -62,7 +62,7 @@ fileprivate func expectFirstMatch( XCTAssertEqual(input.firstMatch(of: r)?.output, output, file: file, line: line) } -#if os(Linux) +#if os(Linux) || os(Android) func XCTExpectFailure(_ message: String? = nil, body: () throws -> Void) rethrows {} #endif From eb7f8017cc57a6069086ca6f7718f15137c1de63 Mon Sep 17 00:00:00 2001 From: Ole Begemann Date: Tue, 6 Dec 2022 20:30:38 +0100 Subject: [PATCH 04/34] Fix documentation typo (#615) --- Sources/RegexBuilder/Anchor.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/RegexBuilder/Anchor.swift b/Sources/RegexBuilder/Anchor.swift index cf1931577..8283b9cbd 100644 --- a/Sources/RegexBuilder/Anchor.swift +++ b/Sources/RegexBuilder/Anchor.swift @@ -81,7 +81,7 @@ extension Anchor { } /// An anchor that matches at the end of the input string or at the end of - /// the line immediately before the the end of the string. + /// the line immediately before the end of the string. /// /// This anchor is equivalent to `\Z` in regex syntax. public static var endOfSubjectBeforeNewline: Anchor { From c51e8f27142a448284458bd687377202d0344488 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Tue, 6 Dec 2022 11:32:47 -0800 Subject: [PATCH 05/34] Fix abstract for Regex.dotMatchesNewlines(_:). (#614) The old version looks like it was accidentally duplicated from anchorsMatchLineEndings(_:) just below it. --- Sources/_StringProcessing/Regex/Options.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index 88d2dbf5d..368a5b634 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -68,8 +68,8 @@ extension Regex { wrapInOption(.unicodeWordBoundaries, addingIf: wordBoundaryKind == .default) } - /// Returns a regular expression where the start and end of input - /// anchors (`^` and `$`) also match against the start and end of a line. + /// Returns a regular expression where the "any" metacharacter (`.`) + /// also matches against the start and end of a line. /// /// - Parameter dotMatchesNewlines: A Boolean value indicating whether `.` /// should match a newline character. From 45f752ab2db496db4396ca796787bbc441739038 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 14 Dec 2022 13:15:24 -0600 Subject: [PATCH 06/34] Remove `RegexConsumer` and fix its dependencies (#617) * Remove `RegexConsumer` and fix its dependencies This eliminates the RegexConsumer type and rewrites its users to call through to other, existing functionality on Regex or in the Algorithms implementations. RegexConsumer doesn't take account of the dual subranges required for matching, so it can produce results that are inconsistent with matches(of:) and ranges(of:), which were rewritten earlier. rdar://102841216 * Remove remaining from-end algorithm methods This removes methods that are left over from when we were considering from-end algorithms. These aren't tested and may not have the correct semantics, so it's safer to remove them entirely. --- .../Algorithms/Algorithms/FirstRange.swift | 17 +- .../Algorithms/Algorithms/Ranges.swift | 83 ------- .../Algorithms/Algorithms/Split.swift | 189 +++------------- .../Algorithms/Algorithms/StartsWith.swift | 43 +--- .../Algorithms/Algorithms/Trim.swift | 209 +----------------- .../Algorithms/Consumers/RegexConsumer.swift | 98 -------- .../Algorithms/Matching/FirstMatch.swift | 15 -- .../Algorithms/Matching/MatchReplace.swift | 39 ---- .../Algorithms/Matching/Matches.swift | 7 - .../Algorithms/Searchers/TwoWaySearcher.swift | 8 + .../RegexTests/AlgorithmsInternalsTests.swift | 8 - Tests/RegexTests/RenderDSLTests.swift | 13 +- 12 files changed, 63 insertions(+), 666 deletions(-) delete mode 100644 Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index 696f36eca..484ff4648 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -20,15 +20,6 @@ extension Collection { } } -extension BidirectionalCollection { - func _lastRange( - of searcher: S - ) -> Range? where S.BackwardSearched == Self { - var state = searcher.backwardState(for: self, in: startIndex.. Range? { - _firstRange(of: RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - func _lastRange(of regex: R) -> Range? { - _lastRange(of: RegexConsumer(regex)) + let s = self[...] + return try? regex.regex.firstMatch(in: s)?.range } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift index fc6b23af2..030ce1f64 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Ranges.swift @@ -115,43 +115,6 @@ extension RangesCollection.Index: Comparable { } } -// MARK: `ReversedRangesCollection` - -struct ReversedRangesCollection { - typealias Base = Searcher.BackwardSearched - - let base: Base - let searcher: Searcher - - init(base: Base, searcher: Searcher) { - self.base = base - self.searcher = searcher - } -} - -extension ReversedRangesCollection: Sequence { - public struct Iterator: IteratorProtocol { - let base: Base - let searcher: Searcher - var state: Searcher.BackwardState - - init(base: Base, searcher: Searcher) { - self.base = base - self.searcher = searcher - self.state = searcher.backwardState( - for: base, in: base.startIndex.. Range? { - searcher.searchBack(base, &state) - } - } - - public func makeIterator() -> Iterator { - Iterator(base: base, searcher: searcher) - } -} - // TODO: `Collection` conformance // MARK: `CollectionSearcher` algorithms @@ -164,14 +127,6 @@ extension Collection { } } -extension BidirectionalCollection { - func _rangesFromBack( - of searcher: S - ) -> ReversedRangesCollection where S.BackwardSearched == Self { - ReversedRangesCollection(base: self, searcher: searcher) - } -} - // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { @@ -195,37 +150,6 @@ extension Collection where Element: Equatable { } } -extension BidirectionalCollection where Element: Equatable { - // FIXME -// public func rangesFromBack( -// of other: S -// ) -> ReversedRangesCollection> -// where S.Element == Element -// { -// fatalError() -// } -} - -extension BidirectionalCollection where Element: Comparable { - func _ranges( - of other: C - ) -> RangesCollection>> - where C.Element == Element - { - _ranges(of: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(other)))) - } - - // FIXME -// public func rangesFromBack( -// of other: S -// ) -> ReversedRangesCollection>> -// where S.Element == Element -// { -// rangesFromBack( -// of: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(other)))) -// } -} - @available(SwiftStdlib 5.7, *) struct RegexRangesCollection { let base: RegexMatchesCollection @@ -299,13 +223,6 @@ extension Collection where SubSequence == Substring { } extension BidirectionalCollection where SubSequence == Substring { - @available(SwiftStdlib 5.7, *) - func _rangesFromBack( - of regex: R - ) -> ReversedRangesCollection> { - _rangesFromBack(of: RegexConsumer(regex)) - } - // FIXME: Return `some Collection>` for SE-0346 /// Finds and returns the ranges of the all occurrences of a given sequence /// within the collection. diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift index 44364df71..6634d2945 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Split.swift @@ -106,121 +106,6 @@ extension SplitCollection: Sequence { } } -//extension SplitCollection: Collection { -// public struct Index { -// var start: Base.Index -// var base: RangesCollection.Index -// var isEndIndex: Bool -// } -// -// public var startIndex: Index { -// let base = ranges.startIndex -// return Index(start: ranges.base.startIndex, base: base, isEndIndex: false) -// } -// -// public var endIndex: Index { -// Index(start: ranges.base.endIndex, base: ranges.endIndex, isEndIndex: true) -// } -// -// public func formIndex(after index: inout Index) { -// guard !index.isEndIndex else { fatalError("Cannot advance past endIndex") } -// -// if let range = index.base.range { -// let newStart = range.upperBound -// ranges.formIndex(after: &index.base) -// index.start = newStart -// } else { -// index.isEndIndex = true -// } -// } -// -// public func index(after index: Index) -> Index { -// var index = index -// formIndex(after: &index) -// return index -// } -// -// public subscript(index: Index) -> Base.SubSequence { -// guard !index.isEndIndex else { -// fatalError("Cannot subscript using endIndex") -// } -// let end = index.base.range?.lowerBound ?? ranges.base.endIndex -// return ranges.base[index.start.. Bool { -// switch (lhs.isEndIndex, rhs.isEndIndex) { -// case (false, false): -// return lhs.start == rhs.start -// case (let lhs, let rhs): -// return lhs == rhs -// } -// } -// -// static func < (lhs: Self, rhs: Self) -> Bool { -// switch (lhs.isEndIndex, rhs.isEndIndex) { -// case (true, _): -// return false -// case (_, true): -// return true -// case (false, false): -// return lhs.start < rhs.start -// } -// } -//} - -// MARK: `ReversedSplitCollection` - -struct ReversedSplitCollection { - public typealias Base = Searcher.BackwardSearched - - let ranges: ReversedRangesCollection - - init(ranges: ReversedRangesCollection) { - self.ranges = ranges - } - - init(base: Base, searcher: Searcher) { - self.ranges = base._rangesFromBack(of: searcher) - } -} - -extension ReversedSplitCollection: Sequence { - public struct Iterator: IteratorProtocol { - let base: Base - var index: Base.Index - var ranges: ReversedRangesCollection.Iterator - var isDone: Bool - - init(ranges: ReversedRangesCollection) { - self.base = ranges.base - self.index = base.endIndex - self.ranges = ranges.makeIterator() - self.isDone = false - } - - public mutating func next() -> Base.SubSequence? { - guard !isDone else { return nil } - - guard let range = ranges.next() else { - isDone = true - return base[.. Iterator { - Iterator(ranges: ranges) - } -} - -// TODO: `Collection` conformance - // MARK: `CollectionSearcher` algorithms extension Collection { @@ -237,16 +122,6 @@ extension Collection { } } -extension BidirectionalCollection { - func splitFromBack( - by separator: Searcher - ) -> ReversedSplitCollection - where Searcher.BackwardSearched == Self - { - ReversedSplitCollection(base: self, searcher: separator) - } -} - // MARK: Predicate algorithms extension Collection { @@ -260,14 +135,6 @@ extension Collection { } } -extension BidirectionalCollection where Element: Equatable { - func splitFromBack( - whereSeparator predicate: @escaping (Element) -> Bool - ) -> ReversedSplitCollection> { - splitFromBack(by: PredicateConsumer(predicate: predicate)) - } -} - // MARK: Single element algorithms extension Collection where Element: Equatable { @@ -280,14 +147,6 @@ extension Collection where Element: Equatable { } } -extension BidirectionalCollection where Element: Equatable { - func splitFromBack( - by separator: Element - ) -> ReversedSplitCollection> { - splitFromBack(whereSeparator: { $0 == separator }) - } -} - // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { @@ -399,21 +258,6 @@ extension StringProtocol where SubSequence == Substring { @available(SwiftStdlib 5.7, *) extension BidirectionalCollection where SubSequence == Substring { - @_disfavoredOverload - func split( - by separator: R, - maxSplits: Int, - omittingEmptySubsequences: Bool - ) -> SplitCollection> { - split(by: RegexConsumer(separator), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) - } - - func splitFromBack( - by separator: R - ) -> ReversedSplitCollection> { - splitFromBack(by: RegexConsumer(separator)) - } - // TODO: Is this @_disfavoredOverload necessary? // It prevents split(separator: String) from choosing this overload instead // of the collection-based version when String has RegexComponent conformance @@ -431,9 +275,34 @@ extension BidirectionalCollection where SubSequence == Substring { maxSplits: Int = .max, omittingEmptySubsequences: Bool = true ) -> [SubSequence] { - Array(split( - by: RegexConsumer(separator), - maxSplits: maxSplits, - omittingEmptySubsequences: omittingEmptySubsequences)) + var result: [SubSequence] = [] + var subSequenceStart = startIndex + + func appendSubsequence(end: Index) -> Bool { + if subSequenceStart == end && omittingEmptySubsequences { + return false + } + result.append(self[subSequenceStart.. 0 && !isEmpty else { + _ = appendSubsequence(end: endIndex) + return result + } + + for match in _matches(of: separator) { + defer { subSequenceStart = match.range.upperBound } + let didAppend = appendSubsequence(end: match.range.lowerBound) + if didAppend && result.count == maxSplits { + break + } + } + + if subSequenceStart != endIndex || !omittingEmptySubsequences { + result.append(self[subSequenceStart..(with consumer: C) -> Bool - where C.Consumed == SubSequence - { - consumer.consuming(self[...]) != nil - } -} - -extension BidirectionalCollection { - func _ends(with consumer: C) -> Bool - where C.Consumed == SubSequence - { - consumer.consumingBack(self[...]) != nil - } -} - -// MARK: Fixed pattern algorithms - -extension Collection where Element: Equatable { - func _starts(with prefix: C) -> Bool - where C.Element == Element - { - _starts(with: FixedPatternConsumer(pattern: prefix)) - } -} - -extension BidirectionalCollection where Element: Equatable { - func _ends(with suffix: C) -> Bool - where C.Element == Element - { - _ends(with: FixedPatternConsumer(pattern: suffix)) - } -} - // MARK: Regex algorithms @available(SwiftStdlib 5.7, *) @@ -56,10 +20,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Returns: `true` if the initial elements of the sequence matches the /// beginning of `regex`; otherwise, `false`. public func starts(with regex: some RegexComponent) -> Bool { - _starts(with: RegexConsumer(regex)) - } - - func _ends(with regex: R) -> Bool { - _ends(with: RegexConsumer(regex)) + let s = self[...] + return (try? regex.regex.prefixMatch(in: s)) != nil } } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index 37f7513db..2908c4dc5 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -41,64 +41,6 @@ extension RangeReplaceableCollection { } } -extension BidirectionalCollection { - func _trimmingSuffix( - _ consumer: Consumer - ) -> SubSequence - where Consumer.Consumed == Self - { - let end = consumer.consumingBack(self) ?? endIndex - return self[..( - _ consumer: Consumer - ) -> SubSequence where Consumer.Consumed == Self { - // NOTE: Might give different results than trimming the suffix before - // trimming the prefix - let start = consumer.consuming(self) ?? startIndex - let end = consumer.consumingBack(self) ?? endIndex - let actualEnd = end < start ? start : end - return self[start..( - _ consumer: Consumer - ) where Consumer.Consumed == SubSequence - { - _ = consumer.consumeBack(&self) - } - - mutating func _trim( - _ consumer: Consumer - ) where Consumer.Consumed == Self { - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} - -extension RangeReplaceableCollection where Self: BidirectionalCollection { - @_disfavoredOverload - mutating func _trimSuffix( - _ consumer: Consumer - ) where Consumer.Consumed == Self - { - if let end = consumer.consumingBack(self) { - removeSubrange(end...) - } - } - - @_disfavoredOverload - mutating func _trim( - _ consumer: Consumer - ) where Consumer.Consumed == Self { - _trimSuffix(consumer) - _trimPrefix(consumer) - } -} - // MARK: Predicate algorithms extension Collection { @@ -136,53 +78,6 @@ extension RangeReplaceableCollection { } } -extension BidirectionalCollection { - func _trimmingSuffix( - while predicate: @escaping (Element) -> Bool - ) -> SubSequence { - _trimmingSuffix(ManyConsumer(base: PredicateConsumer(predicate: predicate))) - } - - func _trimming( - while predicate: @escaping (Element) -> Bool - ) -> SubSequence { - _trimming(ManyConsumer(base: PredicateConsumer(predicate: predicate))) - } -} - -extension BidirectionalCollection where SubSequence == Self { - mutating func _trimSuffix( - while predicate: @escaping (Element) -> Bool - ) { - _trimSuffix(ManyConsumer( - base: PredicateConsumer(predicate: predicate))) - } - - mutating func _trim(while predicate: @escaping (Element) -> Bool) { - let consumer = ManyConsumer( - base: PredicateConsumer(predicate: predicate)) - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} - -extension RangeReplaceableCollection where Self: BidirectionalCollection { - @_disfavoredOverload - mutating func _trimSuffix( - while predicate: @escaping (Element) -> Bool - ) { - _trimSuffix(ManyConsumer(base: PredicateConsumer(predicate: predicate))) - } - - @_disfavoredOverload - mutating func _trim(while predicate: @escaping (Element) -> Bool) { - let consumer = ManyConsumer( - base: PredicateConsumer(predicate: predicate)) - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} - // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { @@ -229,58 +124,6 @@ extension RangeReplaceableCollection where Element: Equatable { } } -extension BidirectionalCollection where Element: Equatable { - func _trimmingSuffix( - _ suffix: Suffix - ) -> SubSequence where Suffix.Element == Element { - _trimmingSuffix(FixedPatternConsumer(pattern: suffix)) - } - - func _trimming( - _ pattern: Pattern - ) -> SubSequence where Pattern.Element == Element { - _trimming(FixedPatternConsumer(pattern: pattern)) - } -} - -extension BidirectionalCollection - where SubSequence == Self, Element: Equatable -{ - mutating func _trimSuffix( - _ suffix: Suffix - ) where Suffix.Element == Element { - _trimSuffix(FixedPatternConsumer(pattern: suffix)) - } - - mutating func _trim( - _ pattern: Pattern - ) where Pattern.Element == Element { - let consumer = FixedPatternConsumer(pattern: pattern) - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} - -extension RangeReplaceableCollection - where Self: BidirectionalCollection, Element: Equatable -{ - @_disfavoredOverload - mutating func _trimSuffix( - _ prefix: Suffix - ) where Suffix.Element == Element { - _trimSuffix(FixedPatternConsumer(pattern: prefix)) - } - - @_disfavoredOverload - mutating func _trim( - _ pattern: Pattern - ) where Pattern.Element == Element { - let consumer = FixedPatternConsumer(pattern: pattern) - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} - // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { @@ -292,17 +135,11 @@ extension BidirectionalCollection where SubSequence == Substring { @_disfavoredOverload @available(SwiftStdlib 5.7, *) public func trimmingPrefix(_ regex: some RegexComponent) -> SubSequence { - _trimmingPrefix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - func _trimmingSuffix(_ regex: R) -> SubSequence { - _trimmingSuffix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - func _trimming(_ regex: R) -> SubSequence { - _trimming(RegexConsumer(regex)) + let s = self[...] + guard let prefix = try? regex.regex.prefixMatch(in: s) else { + return s + } + return s[prefix.range.upperBound...] } } @@ -314,37 +151,11 @@ extension RangeReplaceableCollection @_disfavoredOverload @available(SwiftStdlib 5.7, *) public mutating func trimPrefix(_ regex: some RegexComponent) { - _trimPrefix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - mutating func _trimSuffix(_ regex: R) { - _trimSuffix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - mutating func _trim(_ regex: R) { - let consumer = RegexConsumer(regex) - _trimPrefix(consumer) - _trimSuffix(consumer) + let s = self[...] + guard let prefix = try? regex.regex.prefixMatch(in: s) else { + return + } + self.removeSubrange(prefix.range) } } -extension Substring { - @available(SwiftStdlib 5.7, *) - mutating func _trimPrefix(_ regex: R) { - _trimPrefix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - mutating func _trimSuffix(_ regex: R) { - _trimSuffix(RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - mutating func _trim(_ regex: R) { - let consumer = RegexConsumer(regex) - _trimPrefix(consumer) - _trimSuffix(consumer) - } -} diff --git a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift b/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift deleted file mode 100644 index 4956406da..000000000 --- a/Sources/_StringProcessing/Algorithms/Consumers/RegexConsumer.swift +++ /dev/null @@ -1,98 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// -//===----------------------------------------------------------------------===// - -// FIXME: What even is this? Can we delete this whole thing? -@available(SwiftStdlib 5.7, *) -struct RegexConsumer< - R: RegexComponent, Consumed: BidirectionalCollection -> where Consumed.SubSequence == Substring { - // TODO: Should `Regex` itself implement these protocols? - let regex: R - - init(_ regex: R) { - self.regex = regex - } -} - -@available(SwiftStdlib 5.7, *) -extension RegexConsumer { - func _matchingConsuming( - _ consumed: Substring, in range: Range - ) -> (upperBound: String.Index, match: Match)? { - guard let result = try! regex.regex._match( - consumed.base, - in: range, mode: .partialFromFront - ) else { return nil } - return (result.range.upperBound, result.output) - } -} - -// TODO: Explicitly implement the non-matching consumer/searcher protocols as -// well, taking advantage of the fact that the captures can be ignored - -@available(SwiftStdlib 5.7, *) -extension RegexConsumer: MatchingCollectionConsumer { - typealias Match = R.RegexOutput - - func matchingConsuming( - _ consumed: Consumed, in range: Range - ) -> (upperBound: String.Index, match: Match)? { - _matchingConsuming(consumed[...], in: range) - } -} - -// TODO: We'll want to bake backwards into the engine -@available(SwiftStdlib 5.7, *) -extension RegexConsumer: BidirectionalMatchingCollectionConsumer { - func matchingConsumingBack( - _ consumed: Consumed, in range: Range - ) -> (lowerBound: String.Index, match: Match)? { - var i = range.lowerBound - while true { - if let (end, capture) = _matchingConsuming( - consumed[...], - in: i.. - ) -> (range: Range, match: Match)? { - ConsumerSearcher(consumer: self).matchingSearch(searched, in: range) - } -} - -// TODO: Bake in search-back to engine too -@available(SwiftStdlib 5.7, *) -extension RegexConsumer: BackwardMatchingStatelessCollectionSearcher { - typealias BackwardSearched = Consumed - - func matchingSearchBack( - _ searched: BackwardSearched, in range: Range - ) -> (range: Range, match: Match)? { - ConsumerSearcher(consumer: self).matchingSearchBack(searched, in: range) - } -} diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index c8c6867f4..3ee74f258 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -38,21 +38,6 @@ extension BidirectionalCollection { // MARK: Regex algorithms extension BidirectionalCollection where SubSequence == Substring { - @available(SwiftStdlib 5.7, *) - @_disfavoredOverload - func firstMatch( - of regex: R - ) -> _MatchResult>? { - _firstMatch(of: RegexConsumer(regex)) - } - - @available(SwiftStdlib 5.7, *) - func lastMatch( - of regex: R - ) -> _BackwardMatchResult>? { - lastMatch(of: RegexConsumer(regex)) - } - /// Returns the first match of the specified regex within the collection. /// - Parameter regex: The regex to search for. /// - Returns: The first match of `regex` in the collection, or `nil` if diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index 6bc9b4d77..0f23280ce 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -75,45 +75,6 @@ extension RangeReplaceableCollection { // MARK: Regex algorithms extension RangeReplaceableCollection where SubSequence == Substring { - @available(SwiftStdlib 5.7, *) - func _replacing( - _ regex: R, - with replacement: (_MatchResult>) throws -> Replacement, - subrange: Range, - maxReplacements: Int = .max - ) rethrows -> Self where Replacement.Element == Element { - try _replacing( - RegexConsumer(regex), - with: replacement, - subrange: subrange, - maxReplacements: maxReplacements) - } - - @available(SwiftStdlib 5.7, *) - func _replacing( - _ regex: R, - with replacement: (_MatchResult>) throws -> Replacement, - maxReplacements: Int = .max - ) rethrows -> Self where Replacement.Element == Element { - try _replacing( - regex, - with: replacement, - subrange: startIndex..( - _ regex: R, - with replacement: (_MatchResult>) throws -> Replacement, - maxReplacements: Int = .max - ) rethrows where Replacement.Element == Element { - self = try _replacing( - regex, - with: replacement, - maxReplacements: maxReplacements) - } - /// Returns a new collection in which all occurrences of a sequence matching /// the given regex are replaced by another regex match. /// - Parameters: diff --git a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift index f5c645105..12846bf0f 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/Matches.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/Matches.swift @@ -357,13 +357,6 @@ extension BidirectionalCollection where SubSequence == Substring { regex: regex.regex) } - @available(SwiftStdlib 5.7, *) - func _matchesFromBack( - of regex: R - ) -> ReversedMatchesCollection> { - _matchesFromBack(of: RegexConsumer(regex)) - } - // FIXME: Return `some Collection.Match> for SE-0346 /// Returns a collection containing all matches of the specified regex. /// - Parameter regex: The regex to search for. diff --git a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift index 837493a30..c3537d415 100644 --- a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift +++ b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift @@ -9,6 +9,14 @@ // //===----------------------------------------------------------------------===// +extension BidirectionalCollection where Element: Equatable { + fileprivate func _ends(with suffix: C) -> Bool + where C.Element == Element + { + FixedPatternConsumer(pattern: suffix).consumingBack(self[...]) != nil + } + } + struct TwoWaySearcher where Searched.Element: Comparable { diff --git a/Tests/RegexTests/AlgorithmsInternalsTests.swift b/Tests/RegexTests/AlgorithmsInternalsTests.swift index 96cd12076..af0007bbe 100644 --- a/Tests/RegexTests/AlgorithmsInternalsTests.swift +++ b/Tests/RegexTests/AlgorithmsInternalsTests.swift @@ -24,25 +24,17 @@ extension AlgorithmTests { let str = "a string with the letter b in it" let first = str.firstRange(of: r) - let last = str._lastRange(of: r) let (expectFirst, expectLast) = ( str.index(atOffset: 0).. Bool) -> SubSequence { + var i = endIndex + while i > startIndex { + formIndex(before: &i) + if !predicate(self[i]) { return self[...i] } + } + return self[.. Date: Wed, 14 Dec 2022 13:37:48 -0600 Subject: [PATCH 07/34] Improve StringProcessing and RegexBuilder documentation (#611) This includes documentation improvements for core types/methods, RegexBuilder types along with their generated variadic initializers, and adds some curation. It also includes tests of the documentation code samples. --- .gitignore | 3 + Package.swift | 8 + Sources/RegexBuilder/Anchor.swift | 4 +- Sources/RegexBuilder/Builder.swift | 9 + Sources/RegexBuilder/CharacterClass.swift | 102 +- Sources/RegexBuilder/DSL.swift | 249 +- Sources/RegexBuilder/Variadics.swift | 2431 +++++++++++++++++ .../VariadicsGenerator.swift | 194 ++ .../Documentation.docc/Extensions/Regex.md | 41 + .../Regex/AnyRegexOutput.swift | 186 +- Sources/_StringProcessing/Regex/Core.swift | 63 +- Sources/_StringProcessing/Regex/Match.swift | 222 +- Sources/_StringProcessing/Regex/Options.swift | 23 +- .../RegexBuilderTests.swift | 202 ++ Tests/DocumentationTests/RegexTests.swift | 149 + 15 files changed, 3777 insertions(+), 109 deletions(-) create mode 100644 Sources/_StringProcessing/Documentation.docc/Extensions/Regex.md create mode 100644 Tests/DocumentationTests/RegexBuilderTests.swift create mode 100644 Tests/DocumentationTests/RegexTests.swift diff --git a/.gitignore b/.gitignore index ff85b9fa3..fabf56f96 100644 --- a/.gitignore +++ b/.gitignore @@ -93,3 +93,6 @@ fastlane/test_output # https://github.com/johnno1962/injectionforxcode iOSInjectionProject/ + +# DocC build folder +*.docc-build diff --git a/Package.swift b/Package.swift index 18764fcaf..baeea543f 100644 --- a/Package.swift +++ b/Package.swift @@ -89,6 +89,14 @@ let package = Package( swiftSettings: [ .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) ]), + .testTarget( + name: "DocumentationTests", + dependencies: ["_StringProcessing", "RegexBuilder"], + swiftSettings: [ + .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]), + .unsafeFlags(["-enable-bare-slash-regex"]), + ]), + // FIXME: Disabled due to rdar://94763190. // .testTarget( // name: "Prototypes", diff --git a/Sources/RegexBuilder/Anchor.swift b/Sources/RegexBuilder/Anchor.swift index 8283b9cbd..86be6ce0b 100644 --- a/Sources/RegexBuilder/Anchor.swift +++ b/Sources/RegexBuilder/Anchor.swift @@ -147,7 +147,7 @@ extension Anchor { /// /// Word boundaries are identified using the Unicode default word boundary /// algorithm by default. To specify a different word boundary algorithm, - /// see the `RegexComponent.wordBoundaryKind(_:)` method. + /// use the `wordBoundaryKind(_:)` method. /// /// This anchor is equivalent to `\b` in regex syntax. public static var wordBoundary: Anchor { @@ -157,7 +157,7 @@ extension Anchor { /// The inverse of this anchor, which matches at every position that this /// anchor does not. /// - /// For the `wordBoundary` and `textSegmentBoundary` anchors, the inverted + /// For the ``wordBoundary`` and ``textSegmentBoundary`` anchors, the inverted /// version corresponds to `\B` and `\Y`, respectively. public var inverted: Anchor { var result = self diff --git a/Sources/RegexBuilder/Builder.swift b/Sources/RegexBuilder/Builder.swift index 7afe254c2..4b754c231 100644 --- a/Sources/RegexBuilder/Builder.swift +++ b/Sources/RegexBuilder/Builder.swift @@ -11,6 +11,15 @@ @_spi(RegexBuilder) import _StringProcessing +/// A custom parameter attribute that constructs regular expressions from +/// closures. +/// +/// You typically see `RegexComponentBuilder` as a parameter attribute for +/// `Regex`- or `RegexComponent`-producing closure parameters, allowing those +/// closures to combine multiple regular expression components. Type +/// initializers and string algorithm methods in the RegexBuilder framework +/// include a builder closure parameter, so that you can use regular expression +/// components together. @available(SwiftStdlib 5.7, *) @resultBuilder public enum RegexComponentBuilder { diff --git a/Sources/RegexBuilder/CharacterClass.swift b/Sources/RegexBuilder/CharacterClass.swift index 08c7d347e..cab0ab29b 100644 --- a/Sources/RegexBuilder/CharacterClass.swift +++ b/Sources/RegexBuilder/CharacterClass.swift @@ -12,6 +12,11 @@ @_implementationOnly import _RegexParser @_spi(RegexBuilder) import _StringProcessing +/// A class of characters that match in a regex. +/// +/// A character class can represent individual characters, a group of +/// characters, the set of character that match some set of criteria, or +/// a set algebraic combination of all of the above. @available(SwiftStdlib 5.7, *) public struct CharacterClass { internal var ccc: DSLTree.CustomCharacterClass @@ -42,6 +47,20 @@ extension CharacterClass: RegexComponent { @available(SwiftStdlib 5.7, *) extension CharacterClass { + /// A character class that matches any character that does not match this + /// character class. + /// + /// For example, you can use the `inverted` property to create a character + /// class that excludes a specific group of characters: + /// + /// let validCharacters = CharacterClass("a"..."z", .anyOf("-_")) + /// let invalidCharacters = validCharacters.inverted + /// + /// let username = "user123" + /// if username.contains(invalidCharacters) { + /// print("Invalid username: '\(username)'") + /// } + /// // Prints "Invalid username: 'user123'" public var inverted: CharacterClass { if let inv = builtin?.inverted { return CharacterClass(builtin: inv) @@ -53,26 +72,50 @@ extension CharacterClass { @available(SwiftStdlib 5.7, *) extension RegexComponent where Self == CharacterClass { + /// A character class that matches any element. + /// + /// This character class is unaffected by the `dotMatchesNewlines()` method. + /// To match any character that isn't a newline, see + /// ``anyNonNewline``. + /// + /// This character class is equivalent to the regex syntax "dot" + /// metacharacter in single-line mode: `(?s:.)`. public static var any: CharacterClass { .init(DSLTree.CustomCharacterClass(members: [.atom(.any)])) } + /// A character class that matches any element that isn't a newline. + /// + /// This character class is unaffected by the `dotMatchesNewlines()` method. + /// To match any character, including newlines, see ``any``. + /// + /// This character class is equivalent to the regex syntax "dot" + /// metacharacter with single-line mode disabled: `(?-s:.)`. public static var anyNonNewline: CharacterClass { .init(DSLTree.CustomCharacterClass(members: [.atom(.anyNonNewline)])) } + /// A character class that matches any single `Character`, or extended + /// grapheme cluster, regardless of the current semantic level. + /// + /// This character class is equivalent to `\X` in regex syntax. public static var anyGraphemeCluster: CharacterClass { .init(builtin: .anyGrapheme) } - public static var whitespace: CharacterClass { - .init(builtin: .whitespace) - } - + /// A character class that matches any digit. + /// + /// This character class is equivalent to `\d` in regex syntax. public static var digit: CharacterClass { .init(builtin: .digit) } + /// A character class that matches any hexadecimal digit. + /// + /// `hexDigit` matches the ASCII characters `0` through `9`, and upper- or + /// lowercase `a` through `f`. The corresponding characters in the "Halfwidth + /// and Fullwidth Forms" Unicode block are not matched by this character + /// class. public static var hexDigit: CharacterClass { .init(DSLTree.CustomCharacterClass(members: [ .range(.char("A"), .char("F")), @@ -81,27 +124,56 @@ extension RegexComponent where Self == CharacterClass { ])) } + /// A character class that matches any element that is a "word character". + /// + /// This character class is equivalent to `\w` in regex syntax. + public static var word: CharacterClass { + .init(builtin: .word) + } + + /// A character class that matches any element that is classified as + /// whitespace. + /// + /// This character class is equivalent to `\s` in regex syntax. + public static var whitespace: CharacterClass { + .init(builtin: .whitespace) + } + + /// A character class that matches any element that is classified as + /// horizontal whitespace. + /// + /// This character class is equivalent to `\h` in regex syntax. public static var horizontalWhitespace: CharacterClass { .init(builtin: .horizontalWhitespace) } + /// A character class that matches any newline sequence. + /// + /// This character class is equivalent to `\R` or `\n` in regex syntax. public static var newlineSequence: CharacterClass { .init(builtin: .newlineSequence) } + /// A character class that matches any element that is classified as + /// vertical whitespace. + /// + /// This character class is equivalent to `\v` in regex syntax. public static var verticalWhitespace: CharacterClass { .init(builtin: .verticalWhitespace) } - - public static var word: CharacterClass { - .init(builtin: .word) - } } @available(SwiftStdlib 5.7, *) extension RegexComponent where Self == CharacterClass { /// Returns a character class that matches any character in the given string /// or sequence. + /// + /// Calling this method with a group of characters is equivalent to listing + /// those characters in a custom character class in regex syntax. For example, + /// the two regexes in this example are equivalent: + /// + /// let regex1 = /[abcd]+/ + /// let regex2 = OneOrMore(.anyOf("abcd")) public static func anyOf(_ s: S) -> CharacterClass where S.Element == Character { @@ -111,6 +183,9 @@ extension RegexComponent where Self == CharacterClass { /// Returns a character class that matches any Unicode scalar in the given /// sequence. + /// + /// Calling this method with a group of Unicode scalars is equivalent to + /// listing them in a custom character class in regex syntax. public static func anyOf(_ s: S) -> CharacterClass where S.Element == UnicodeScalar { @@ -122,6 +197,11 @@ extension RegexComponent where Self == CharacterClass { // Unicode properties @available(SwiftStdlib 5.7, *) extension CharacterClass { + /// Returns a character class that matches any element with the given Unicode + /// general category. + /// + /// For example, when passed `.uppercaseLetter`, this method is equivalent to + /// `/\p{Uppercase_Letter}/` or `/\p{Lu}/`. public static func generalCategory(_ category: Unicode.GeneralCategory) -> CharacterClass { return CharacterClass(.generalCategory(category)) } @@ -148,6 +228,7 @@ public func ...(lhs: UnicodeScalar, rhs: UnicodeScalar) -> CharacterClass { @available(SwiftStdlib 5.7, *) extension RegexComponent where Self == CharacterClass { + /// Creates a character class that combines the given classes in a union. public init(_ first: CharacterClass, _ rest: CharacterClass...) { if rest.isEmpty { self.init(first.ccc) @@ -161,24 +242,29 @@ extension RegexComponent where Self == CharacterClass { @available(SwiftStdlib 5.7, *) extension CharacterClass { + /// Returns a character class from the union of this class and the given class. public func union(_ other: CharacterClass) -> CharacterClass { CharacterClass(.init(members: [ .custom(self.ccc), .custom(other.ccc)])) } + /// Returns a character class from the intersection of this class and the given class. public func intersection(_ other: CharacterClass) -> CharacterClass { CharacterClass(.init(members: [ .intersection(self.ccc, other.ccc) ])) } + /// Returns a character class by subtracting the given class from this class. public func subtracting(_ other: CharacterClass) -> CharacterClass { CharacterClass(.init(members: [ .subtraction(self.ccc, other.ccc) ])) } + /// Returns a character class matching elements in one or the other, but not both, + /// of this class and the given class. public func symmetricDifference(_ other: CharacterClass) -> CharacterClass { CharacterClass(.init(members: [ .symmetricDifference(self.ccc, other.ccc) diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index e758999ef..152aadd0c 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -14,6 +14,7 @@ @available(SwiftStdlib 5.7, *) extension Regex { + /// Creates a regular expression using a RegexBuilder closure. public init( @RegexComponentBuilder _ content: () -> Content ) where Content.RegexOutput == Output { @@ -89,6 +90,7 @@ extension UnicodeScalar: RegexComponent { public struct One: RegexComponent { public var regex: Regex + /// Creates a regex component that matches the given component exactly once. public init( _ component: Component ) where Component.RegexOutput == Output { @@ -96,6 +98,8 @@ public struct One: RegexComponent { } } +/// A regex component that matches one or more occurrences of its underlying +/// component. @available(SwiftStdlib 5.7, *) public struct OneOrMore: _BuiltinRegexComponent { public var regex: Regex @@ -109,6 +113,8 @@ public struct OneOrMore: _BuiltinRegexComponent { // Variadics.swift. } +/// A regex component that matches zero or more occurrences of its underlying +/// component. @available(SwiftStdlib 5.7, *) public struct ZeroOrMore: _BuiltinRegexComponent { public var regex: Regex @@ -122,6 +128,8 @@ public struct ZeroOrMore: _BuiltinRegexComponent { // Variadics.swift. } +/// A regex component that matches zero or one occurrences of its underlying +/// component. @available(SwiftStdlib 5.7, *) public struct Optionally: _BuiltinRegexComponent { public var regex: Regex @@ -135,6 +143,8 @@ public struct Optionally: _BuiltinRegexComponent { // Variadics.swift. } +/// A regex component that matches a selectable number of occurrences of its +/// underlying component. @available(SwiftStdlib 5.7, *) public struct Repeat: _BuiltinRegexComponent { public var regex: Regex @@ -162,6 +172,12 @@ public struct Repeat: _BuiltinRegexComponent { // ) -> R where R.Match == (W, C...) // } +/// A custom parameter attribute that constructs regular expression alternations +/// from closures. +/// +/// When you use a `ChoiceOf` initializer, the initializer's +/// closure parameter has an `AlternationBuilder` attribute, allowing you +/// to provide multiple regular expression statements as alternatives. @available(SwiftStdlib 5.7, *) @resultBuilder public struct AlternationBuilder { @@ -177,6 +193,22 @@ public struct AlternationBuilder { } } +/// A regex component that chooses exactly one of its constituent regex +/// components when matching. +/// +/// You can use `ChoiceOf` to provide a group of regex components, each of +/// which can be exclusively matched. In this example, `regex` successfully +/// matches either a `"CREDIT"` or `"DEBIT"` substring: +/// +/// let regex = Regex { +/// ChoiceOf { +/// "CREDIT" +/// "DEBIT" +/// } +/// } +/// let match = try regex.prefixMatch(in: "DEBIT 04032020 Payroll $69.73") +/// print(match?.0 as Any) +/// // Prints "DEBIT" @available(SwiftStdlib 5.7, *) public struct ChoiceOf: _BuiltinRegexComponent { public var regex: Regex @@ -186,6 +218,24 @@ public struct ChoiceOf: _BuiltinRegexComponent { self.regex = regex } + /// Creates a regex component that chooses exactly one of the regex components + /// provided by the builder closure. + /// + /// In this example, `regex` successfully matches either a `"CREDIT"` or + /// `"DEBIT"` substring: + /// + /// let regex = Regex { + /// ChoiceOf { + /// "CREDIT" + /// "DEBIT" + /// } + /// } + /// let match = try regex.prefixMatch(in: "DEBIT 04032020 Payroll $69.73") + /// print(match?.0 as Any) + /// // Prints "DEBIT" + /// + /// - Parameter builder: A builder closure that declares a list of regex + /// components, each of which can be exclusively matched. public init(@AlternationBuilder _ builder: () -> Self) { self = builder() } @@ -193,6 +243,71 @@ public struct ChoiceOf: _BuiltinRegexComponent { // MARK: - Capture +/// A regex component that saves the matched substring, or a transformed result, +/// for access in a regex match. +/// +/// Use a `Capture` component to capture one part of a regex to access +/// separately after matching. In the example below, `regex` matches a dollar +/// sign (`"$"`) followed by one or more digits, a period (`"."`), and then two +/// additional digits, as long as that pattern appears at the end of the line. +/// Because the `Capture` block wraps the digits and period, that part of the +/// match is captured separately. +/// +/// let transactions = """ +/// CREDIT 109912311421 Payroll $69.73 +/// CREDIT 105912031123 Travel $121.54 +/// DEBIT 107733291022 Refund $8.42 +/// """ +/// +/// let regex = Regex { +/// "$" +/// Capture { +/// OneOrMore(.digit) +/// "." +/// Repeat(.digit, count: 2) +/// } +/// Anchor.endOfLine +/// } +/// +/// // The type of each match's output is `(Substring, Substring)`. +/// for match in transactions.matches(of: regex) { +/// print("Transaction amount: \(match.1)") +/// } +/// // Prints "Transaction amount: 69.73" +/// // Prints "Transaction amount: 121.54" +/// // Prints "Transaction amount: 8.42" +/// +/// Each `Capture` block increases the number of components in the regex's +/// output type. In the example above, the capture type of each match is +/// `(Substring, Substring)`. +/// +/// By providing a transform function to the `Capture` block, you can change the +/// type of the captured value from `Substring` to the result of the transform. +/// This example declares `doubleValueRegex`, which converts the captured amount +/// to a `Double`: +/// +/// let doubleValueRegex = Regex { +/// "$" +/// Capture { +/// OneOrMore(.digit) +/// "." +/// Repeat(.digit, count: 2) +/// } transform: { Double($0)! } +/// Anchor.endOfLine +/// } +/// +/// // The type of each match's output is `(Substring, Double)`. +/// for match in transactions.matches(of: doubleValueRegex) { +/// if match.1 >= 100.0 { +/// print("Large amount: \(match.1)") +/// } +/// } +/// // Prints "Large amount: 121.54" +/// +/// Throwing an error from a `transform` closure aborts matching and propagates +/// the error out to the caller. If you instead want to use a failable +/// transformation, where a `nil` result participates in matching, use +/// ``TryCapture`` instead of `Capture`. @available(SwiftStdlib 5.7, *) public struct Capture: _BuiltinRegexComponent { public var regex: Regex @@ -205,6 +320,61 @@ public struct Capture: _BuiltinRegexComponent { // Note: Public initializers are currently gyb'd. See Variadics.swift. } +/// A regex component that attempts to transform a matched substring, saving +/// the result if successful and backtracking if the transformation fails. +/// +/// You use a `TryCapture` component to capture part of a match as a +/// transformed value, when a failure to transform should mean the regex +/// continues matching, backtracking from that point if necessary. +/// +/// The code below demonstrates using `TryCapture` to include a test that the +/// `Double` value of a capture is over a limit. In the example, `regex` +/// matches a dollar sign (`"$"`) followed by one or more digits, a period +/// (`"."`), and then two additional digits, as long as that pattern appears at +/// the end of the line. The `TryCapture` block wraps the digits and period, +/// capturing that part of the match separately and passing it to its +/// `transform` closure. That closure converts the captured portion of the +/// match, converts it to a `Double`, and only returns a non-`nil` value if it +/// is over the transaction limit. +/// +/// let transactions = """ +/// CREDIT 109912311421 Payroll $69.73 +/// CREDIT 105912031123 Travel $121.54 +/// DEBIT 107733291022 Refund $8.42 +/// """ +/// let transactionLimit = 100.0 +/// +/// let regex = Regex { +/// "$" +/// TryCapture { +/// OneOrMore(.digit) +/// "." +/// Repeat(.digit, count: 2) +/// } transform: { str -> Double? in +/// let value = Double(str)! +/// if value > transactionLimit { +/// return value +/// } +/// return nil +/// } +/// Anchor.endOfLine +/// } +/// +/// When the `TryCapture` block's `transform` closure processes the three +/// different amounts in the list of transactions, it only returns a non-`nil` +/// value for the $121.54 transaction. Even though the capture returns an +/// optional `Double` value, the captured value is non-optional. +/// +/// // The type of each match's output is `(Substring, Double)`. +/// for match in transactions.matches(of: regex) { +/// print("Transaction amount: \(match.1)") +/// } +/// // Prints "Transaction amount: 121.54" +/// +/// Throwing an error from a `transform` closure aborts matching and propagates +/// the error out to the caller. If you want to capture the `nil` results of a +/// failable transformation, instead of continuing a search, use ``Capture`` +/// instead of `TryCapture`. @available(SwiftStdlib 5.7, *) public struct TryCapture: _BuiltinRegexComponent { public var regex: Regex @@ -219,10 +389,10 @@ public struct TryCapture: _BuiltinRegexComponent { // MARK: - Groups -/// An atomic group. +/// A regex component that represents an atomic group. /// -/// This group opens a local backtracking scope which, upon successful exit, -/// discards any remaining backtracking points from within the scope. +/// An atomic group opens a local backtracking scope which, upon successful +/// exit, discards any remaining backtracking points from within the scope. @available(SwiftStdlib 5.7, *) public struct Local: _BuiltinRegexComponent { public var regex: Regex @@ -235,11 +405,81 @@ public struct Local: _BuiltinRegexComponent { // MARK: - Backreference +/// A reference to a captured portion of a regular expression. +/// +/// You can use a `Reference` to access a regular expression, both during +/// the matching process and after a capture has been successful. +/// +/// In this example, the `kind` reference captures either `"CREDIT"` or +/// `"DEBIT"` at the beginning of a line. Later in the regular expression, the +/// presence of `kind` matches the same substring that was captured previously +/// at the end of the line. +/// +/// let kindRef = Reference(Substring.self) +/// let kindRegex = ChoiceOf { +/// "CREDIT" +/// "DEBIT" +/// } +/// +/// let transactionRegex = Regex { +/// Anchor.startOfLine +/// Capture(kindRegex, as: kindRef) +/// OneOrMore(.anyNonNewline) +/// kindRef +/// Anchor.endOfLine +/// } +/// +/// let validTransaction = "CREDIT 109912311421 Payroll $69.73 CREDIT" +/// let invalidTransaction = "DEBIT 00522142123 Expense $5.17 CREDIT" +/// +/// print(validTransaction.contains(transactionRegex)) +/// // Prints "true" +/// print(invalidTransaction.contains(transactionRegex)) +/// // Prints "false" +/// +/// Any reference that is used for matching must be captured elsewhere in the +/// `Regex` block. You can use a reference for matching before it is captured; +/// in that case, the reference will not match until it has previously been +/// captured. +/// +/// To access the captured "transaction kind", you can use the `kind` reference +/// to subscript a `Regex.Match` instance: +/// +/// if let match = validTransaction.firstMatch(of: transactionRegex) { +/// print(match[kindRef]) +/// } +/// // Prints "CREDIT" +/// +/// To use a `Reference` to capture a transformed value, include a `transform` +/// closure when capturing. +/// +/// struct Transaction { +/// var id: UInt64 +/// } +/// let transactionRef = Reference(Transaction.self) +/// +/// let transactionIDRegex = Regex { +/// Capture(kindRegex, as: kindRef) +/// OneOrMore(.whitespace) +/// TryCapture(as: transactionRef) { +/// OneOrMore(.digit) +/// } transform: { str in +/// UInt64(str).map(Transaction.init(id:)) +/// } +/// OneOrMore(.anyNonNewline) +/// kindRef +/// Anchor.endOfLine +/// } +/// +/// if let match = validTransaction.firstMatch(of: transactionIDRegex) { +/// print(match[transactionRef]) +/// } +/// // Prints "Transaction(id: 109912311421)" @available(SwiftStdlib 5.7, *) -/// A backreference. public struct Reference: RegexComponent { let id = ReferenceID() + /// Creates a reference with the specified capture type. public init(_ captureType: Capture.Type = Capture.self) {} @usableFromInline @@ -254,6 +494,7 @@ public struct Reference: RegexComponent { @available(SwiftStdlib 5.7, *) extension Regex.Match { + /// Accesses this match's capture by the given reference. public subscript(_ reference: Reference) -> Capture { self[reference.id] } diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index 7336f0a30..0f19cd6b0 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -688,6 +688,16 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -701,6 +711,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -724,6 +745,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -737,6 +768,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -751,6 +793,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -764,6 +816,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -778,6 +841,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -789,6 +859,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -800,6 +878,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -811,6 +901,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( @@ -824,6 +927,16 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -836,6 +949,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -858,6 +982,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -870,6 +1004,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -883,6 +1028,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -895,6 +1050,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -908,6 +1074,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_alwaysEmitIntoClient public init( _ component: Component, @@ -918,6 +1091,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_alwaysEmitIntoClient public init( count: Int, @@ -928,6 +1109,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -938,6 +1131,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( _ expression: R, @@ -950,6 +1156,16 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -962,6 +1178,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -984,6 +1211,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -996,6 +1233,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1009,6 +1257,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1021,6 +1279,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1034,6 +1303,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1044,6 +1320,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_alwaysEmitIntoClient public init( count: Int, @@ -1054,6 +1338,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1064,6 +1360,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( _ expression: R, @@ -1076,6 +1385,16 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1088,6 +1407,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1110,6 +1440,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1122,6 +1462,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1135,6 +1486,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1147,6 +1508,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1160,6 +1532,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1170,6 +1549,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_alwaysEmitIntoClient public init( count: Int, @@ -1180,6 +1567,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1190,6 +1589,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( _ expression: R, @@ -1202,6 +1614,16 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1214,6 +1636,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1236,6 +1669,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1248,6 +1691,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1261,6 +1715,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1273,6 +1737,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1286,6 +1761,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1296,6 +1778,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_alwaysEmitIntoClient public init( count: Int, @@ -1306,6 +1796,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1316,6 +1818,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( _ expression: R, @@ -1328,6 +1843,16 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1340,6 +1865,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1362,6 +1898,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1374,6 +1920,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1387,6 +1944,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1399,6 +1966,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1412,6 +1990,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1422,6 +2007,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_alwaysEmitIntoClient public init( count: Int, @@ -1432,6 +2025,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1442,6 +2047,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( _ expression: R, @@ -1454,6 +2072,16 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1466,6 +2094,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1488,6 +2127,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1500,6 +2149,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1513,6 +2173,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1525,6 +2195,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1538,6 +2219,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1548,6 +2236,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_alwaysEmitIntoClient public init( count: Int, @@ -1558,6 +2254,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1568,6 +2276,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( _ expression: R, @@ -1580,6 +2301,16 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1592,6 +2323,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1614,6 +2356,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1626,6 +2378,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1639,6 +2402,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1651,6 +2424,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1664,6 +2448,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1674,6 +2465,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_alwaysEmitIntoClient public init( count: Int, @@ -1684,6 +2483,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1694,6 +2505,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( _ expression: R, @@ -1706,6 +2530,16 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1718,6 +2552,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1740,6 +2585,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1752,6 +2607,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1765,6 +2631,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1777,6 +2653,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1790,6 +2677,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1800,6 +2694,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_alwaysEmitIntoClient public init( count: Int, @@ -1810,6 +2712,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1820,6 +2734,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( _ expression: R, @@ -1832,6 +2759,16 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1844,6 +2781,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1866,6 +2814,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1878,6 +2836,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1891,6 +2860,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1903,6 +2882,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1916,6 +2906,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1926,6 +2923,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_alwaysEmitIntoClient public init( count: Int, @@ -1936,6 +2941,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1946,6 +2963,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( _ expression: R, @@ -1958,6 +2988,16 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -1970,6 +3010,17 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension Optionally { + /// Creates a regex component that matches the given component + /// zero or one times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -1992,6 +3043,16 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -2004,6 +3065,17 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension ZeroOrMore { + /// Creates a regex component that matches the given component + /// zero or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -2017,6 +3089,16 @@ extension ZeroOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -2029,6 +3111,17 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension OneOrMore { + /// Creates a regex component that matches the given component + /// one or more times. + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. @_alwaysEmitIntoClient public init( _ behavior: RegexRepetitionBehavior? = nil, @@ -2042,6 +3135,13 @@ extension OneOrMore { @available(SwiftStdlib 5.7, *) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. @_alwaysEmitIntoClient public init( _ component: Component, @@ -2052,6 +3152,14 @@ extension Repeat { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. @_alwaysEmitIntoClient public init( count: Int, @@ -2062,6 +3170,18 @@ extension Repeat { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. @_alwaysEmitIntoClient public init( _ component: Component, @@ -2072,6 +3192,19 @@ extension Repeat { self.init(factory.repeating(expression.relative(to: 0..( _ expression: R, @@ -2084,6 +3217,10 @@ extension Repeat { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_disfavoredOverload @_alwaysEmitIntoClient @@ -2097,6 +3234,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_disfavoredOverload @_alwaysEmitIntoClient @@ -2109,6 +3250,10 @@ extension Local { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2121,6 +3266,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2132,6 +3281,10 @@ extension Local { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2144,6 +3297,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2155,6 +3312,10 @@ extension Local { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2167,6 +3328,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2178,6 +3343,10 @@ extension Local { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2190,6 +3359,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2201,6 +3374,10 @@ extension Local { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2213,6 +3390,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2224,6 +3405,10 @@ extension Local { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2236,6 +3421,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2247,6 +3436,10 @@ extension Local { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2259,6 +3452,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2270,6 +3467,10 @@ extension Local { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2282,6 +3483,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2293,6 +3498,10 @@ extension Local { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2305,6 +3514,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2316,6 +3529,10 @@ extension Local { } @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -2328,6 +3545,10 @@ extension Local { @available(SwiftStdlib 5.7, *) extension Local { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public init( @@ -3071,6 +4292,9 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3080,6 +4304,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3089,6 +4320,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3099,6 +4339,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3113,6 +4364,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3123,6 +4384,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3139,6 +4412,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3148,6 +4425,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3158,6 +4443,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3168,6 +4463,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3182,6 +4489,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3192,6 +4510,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient public init( @@ -3208,6 +4539,9 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient public init( _ component: R @@ -3216,6 +4550,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_alwaysEmitIntoClient public init( _ component: R, as reference: Reference @@ -3224,6 +4565,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3233,6 +4583,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3246,6 +4607,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3255,6 +4626,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3270,6 +4653,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R @@ -3278,6 +4665,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3287,6 +4682,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3296,6 +4701,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3309,6 +4726,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3318,6 +4746,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3333,6 +4774,9 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient public init( _ component: R @@ -3341,6 +4785,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_alwaysEmitIntoClient public init( _ component: R, as reference: Reference @@ -3349,6 +4800,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3358,6 +4818,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3371,6 +4842,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3380,6 +4861,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3395,6 +4888,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R @@ -3403,6 +4900,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3412,6 +4917,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3421,6 +4936,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3434,6 +4961,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3443,6 +4981,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3458,6 +5009,9 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient public init( _ component: R @@ -3466,6 +5020,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_alwaysEmitIntoClient public init( _ component: R, as reference: Reference @@ -3474,6 +5035,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3483,6 +5053,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3496,6 +5077,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3505,6 +5096,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3520,6 +5123,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R @@ -3528,6 +5135,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3537,6 +5152,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3546,6 +5171,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3559,6 +5196,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3568,6 +5216,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3583,6 +5244,9 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient public init( _ component: R @@ -3591,6 +5255,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_alwaysEmitIntoClient public init( _ component: R, as reference: Reference @@ -3599,6 +5270,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3608,6 +5288,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3621,6 +5312,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3630,6 +5331,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3645,6 +5358,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R @@ -3653,6 +5370,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3662,6 +5387,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3671,6 +5406,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3684,6 +5431,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3693,6 +5451,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3708,6 +5479,9 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient public init( _ component: R @@ -3716,6 +5490,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_alwaysEmitIntoClient public init( _ component: R, as reference: Reference @@ -3724,6 +5505,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3733,6 +5523,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3746,6 +5547,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3755,6 +5566,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3770,6 +5593,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R @@ -3778,6 +5605,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3787,6 +5622,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3796,6 +5641,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3809,6 +5666,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3818,6 +5686,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3833,6 +5714,9 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient public init( _ component: R @@ -3841,6 +5725,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_alwaysEmitIntoClient public init( _ component: R, as reference: Reference @@ -3849,6 +5740,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3858,6 +5758,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3871,6 +5782,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3880,6 +5801,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3895,6 +5828,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R @@ -3903,6 +5840,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3912,6 +5857,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3921,6 +5876,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3934,6 +5901,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -3943,6 +5921,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -3958,6 +5949,9 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient public init( _ component: R @@ -3966,6 +5960,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_alwaysEmitIntoClient public init( _ component: R, as reference: Reference @@ -3974,6 +5975,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3983,6 +5993,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -3996,6 +6017,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4005,6 +6036,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4020,6 +6063,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R @@ -4028,6 +6075,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4037,6 +6092,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -4046,6 +6111,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4059,6 +6136,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -4068,6 +6156,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4083,6 +6184,9 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient public init( _ component: R @@ -4091,6 +6195,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_alwaysEmitIntoClient public init( _ component: R, as reference: Reference @@ -4099,6 +6210,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4108,6 +6228,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4121,6 +6252,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4130,6 +6271,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4145,6 +6298,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R @@ -4153,6 +6310,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4162,6 +6327,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -4171,6 +6346,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4184,6 +6371,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -4193,6 +6391,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4208,6 +6419,9 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient public init( _ component: R @@ -4216,6 +6430,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_alwaysEmitIntoClient public init( _ component: R, as reference: Reference @@ -4224,6 +6445,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4233,6 +6463,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4246,6 +6487,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4255,6 +6506,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4270,6 +6533,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R @@ -4278,6 +6545,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4287,6 +6562,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -4296,6 +6581,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4309,6 +6606,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -4318,6 +6626,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4333,6 +6654,9 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient public init( _ component: R @@ -4341,6 +6665,13 @@ extension Capture { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. @_alwaysEmitIntoClient public init( _ component: R, as reference: Reference @@ -4349,6 +6680,15 @@ extension Capture { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4358,6 +6698,17 @@ extension Capture { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4371,6 +6722,16 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4380,6 +6741,18 @@ extension TryCapture { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( _ component: R, @@ -4395,6 +6768,10 @@ extension TryCapture { @available(SwiftStdlib 5.7, *) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R @@ -4403,6 +6780,14 @@ extension Capture { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4412,6 +6797,16 @@ extension Capture { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -4421,6 +6816,18 @@ extension Capture { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, @@ -4434,6 +6841,17 @@ extension Capture { @available(SwiftStdlib 5.7, *) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( @RegexComponentBuilder _ componentBuilder: () -> R, @@ -4443,6 +6861,19 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. @_alwaysEmitIntoClient public init( as reference: Reference, diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index 8ddaee145..180bfb168 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -335,6 +335,23 @@ struct VariadicsGenerator: ParsableCommand { case .oneOrMore: return "oneOrMore" } } + + var commentAbstract: String { + switch self { + case .zeroOrOne: return """ + /// Creates a regex component that matches the given component + /// zero or one times. + """ + case .zeroOrMore: return """ + /// Creates a regex component that matches the given component + /// zero or more times. + """ + case .oneOrMore: return """ + /// Creates a regex component that matches the given component + /// one or more times. + """ + } + } } struct QuantifierParameters { @@ -389,6 +406,15 @@ struct VariadicsGenerator: ParsableCommand { output(""" \(defaultAvailableAttr) extension \(kind.rawValue) { + \(kind.commentAbstract) + /// + /// - Parameters: + /// - component: The regex component. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. \(params.disfavored)\ @_alwaysEmitIntoClient public init<\(params.genericParams)>( @@ -402,6 +428,16 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension \(kind.rawValue) { + \(kind.commentAbstract) + /// + /// - Parameters: + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. + /// - componentBuilder: A builder closure that generates a regex + /// component. \(params.disfavored)\ @_alwaysEmitIntoClient public init<\(params.genericParams)>( @@ -461,6 +497,10 @@ struct VariadicsGenerator: ParsableCommand { output(""" \(defaultAvailableAttr) extension \(groupName) { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter component: The regex component to wrap in an atomic + /// group. \(defaultAvailableAttr) \(disfavored)\ @_alwaysEmitIntoClient @@ -474,6 +514,10 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension \(groupName) { + /// Creates an atomic group with the given regex component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to wrap in an atomic group. \(defaultAvailableAttr) \(disfavored)\ @_alwaysEmitIntoClient @@ -499,6 +543,13 @@ struct VariadicsGenerator: ParsableCommand { output(""" \(defaultAvailableAttr) extension Repeat { + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. \(params.disfavored)\ @_alwaysEmitIntoClient public init<\(params.genericParams)>( @@ -510,6 +561,14 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.exactly(count, component)) } + /// Creates a regex component that matches the given component repeated + /// the specified number of times. + /// + /// - Parameters: + /// - count: The number of times to repeat `component`. `count` must + /// be greater than or equal to zero. + /// - componentBuilder: A builder closure that creates the regex + /// component to repeat. \(params.disfavored)\ @_alwaysEmitIntoClient public init<\(params.genericParams)>( @@ -521,6 +580,18 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.exactly(count, componentBuilder())) } + /// Creates a regex component that matches the given component repeated + /// a number of times specified by the given range expression. + /// + /// - Parameters: + /// - component: The regex component to repeat. + /// - expression: A range expression specifying the number of times + /// that `component` can repeat. + /// - behavior: The repetition behavior to use when repeating + /// `component` in the match. If `behavior` is `nil`, the default + /// repetition behavior is used, which can be changed from + /// `eager` by calling `repetitionBehavior(_:)` on the resulting + /// `Regex`. \(params.disfavored)\ @_alwaysEmitIntoClient public init<\(params.genericParams), R: RangeExpression>( @@ -532,6 +603,19 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.repeating(expression.relative(to: 0..( @@ -649,6 +733,9 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter component: The regex component to capture. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams)>( @@ -658,6 +745,13 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.capture(component)) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams)>( @@ -667,6 +761,15 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.capture(component, reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( @@ -677,6 +780,17 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.capture(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( @@ -691,6 +805,16 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( @@ -701,6 +825,18 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.captureOptional(component, nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - component: The regex component to capture. + /// - reference: The reference to use for anything captured by + /// `component`. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( @@ -717,6 +853,10 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension Capture { + /// Creates a capture for the given component. + /// + /// - Parameter componentBuilder: A builder closure that generates a + /// regex component to capture. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams)>( @@ -726,6 +866,14 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.capture(componentBuilder())) } + /// Creates a capture for the given component using the specified + /// reference. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams)>( @@ -736,6 +884,16 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.capture(componentBuilder(), reference._raw)) } + /// Creates a capture for the given component, transforming with the + /// given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( @@ -746,6 +904,18 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.capture(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, transforming with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( @@ -760,6 +930,17 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension TryCapture { + /// Creates a capture for the given component, attempting to transform + /// with the given closure. + /// + /// - Parameters: + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( @@ -770,6 +951,19 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.captureOptional(componentBuilder(), nil, transform)) } + /// Creates a capture for the given component using the specified + /// reference, attempting to transform with the given closure. + /// + /// - Parameters: + /// - reference: The reference to use for anything captured by + /// `component`. + /// - componentBuilder: A builder closure that generates a regex + /// component to capture. + /// - transform: A closure that takes the substring matched by + /// `component` and returns a new value to capture, or `nil` if + /// matching should proceed, backtracking if allowed. If `transform` + /// throws an error, matching is abandoned and the error is returned + /// to the caller. \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( diff --git a/Sources/_StringProcessing/Documentation.docc/Extensions/Regex.md b/Sources/_StringProcessing/Documentation.docc/Extensions/Regex.md new file mode 100644 index 000000000..69852efb9 --- /dev/null +++ b/Sources/_StringProcessing/Documentation.docc/Extensions/Regex.md @@ -0,0 +1,41 @@ +# ``_StringProcessing/Regex`` + +## Topics + +### Creating a Regex + +- ``init(_:)-52kg`` +- ``init(_:as:)-5z5nu`` +- ``init(verbatim:)`` + +### Converting Different Outputs + +- ``init(_:)-92siq`` +- ``init(_:as:)-2ucu7`` + +### Searching in Strings + +- ``firstMatch(in:)-6s8x0`` +- ``firstMatch(in:)-45hz7`` +- ``prefixMatch(in:)-5oh8i`` +- ``prefixMatch(in:)-1an24`` +- ``wholeMatch(in:)-9do8t`` +- ``wholeMatch(in:)-8hr88`` + +### Inspecting a Regex + +- ``regex`` +- ``contains(captureNamed:)`` + +### Setting Options + +- ``ignoresCase(_:)`` +- ``dotMatchesNewlines(_:)`` +- ``anchorsMatchLineEndings(_:)`` +- ``repetitionBehavior(_:)`` +- ``matchingSemantics(_:)`` +- ``wordBoundaryKind(_:)`` +- ``asciiOnlyDigits(_:)`` +- ``asciiOnlyWhitespace(_:)`` +- ``asciiOnlyWordCharacters(_:)`` +- ``asciiOnlyCharacterClasses(_:)`` diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index 0cf27af6b..fd292ed1b 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -11,7 +11,10 @@ @_implementationOnly import _RegexParser -/// A type-erased regex output. +/// The type-erased, dynamic output of a regular expression match. +/// +/// When you find a match using regular expression that has `AnyRegexOutput` +/// as its output type, you can find information about matches by iterating @available(SwiftStdlib 5.7, *) public struct AnyRegexOutput { internal let input: String @@ -20,21 +23,22 @@ public struct AnyRegexOutput { @available(SwiftStdlib 5.7, *) extension AnyRegexOutput { - /// Creates a type-erased regex output from an existing match. + /// Creates a dynamic regular expression match output from an existing match. /// - /// Use this initializer to fit a strongly-typed regex match into the - /// use site of a type-erased regex output. + /// You can use this initializer when you need an `AnyRegexOutput` instance + /// instead of the output type of a strongly-typed `Regex.Match`. public init(_ match: Regex.Match) { self = match.anyRegexOutput } - /// Returns a strongly-typed output by converting type-erased values to the specified type. + /// Returns strongly-typed match output by converting this type-erased + /// output to the specified type, if possible. /// - /// - Parameter type: The expected output type. - /// - Returns: The output, if the underlying value can be converted to the - /// output type; otherwise `nil`. + /// - Parameter outputType: The expected output type. + /// - Returns: The output, if the underlying value can be converted to + /// `outputType`; otherwise, `nil`. public func extractValues( - as type: Output.Type = Output.self + as outputType: Output.Type = Output.self ) -> Output? { let elements = map { $0.existentialOutputComponent(from: input) @@ -45,31 +49,40 @@ extension AnyRegexOutput { @available(SwiftStdlib 5.7, *) extension AnyRegexOutput: RandomAccessCollection { - /// An individual type-erased output value. + /// An individual match output value. public struct Element { internal let representation: ElementRepresentation internal let input: String - /// The range over which a value was captured. `nil` for no-capture. + /// The range over which a value was captured, if there was a capture. + /// + /// If nothing was captured, `range` is `nil`. public var range: Range? { representation.content?.range } - /// The slice of the input over which a value was captured. `nil` for no-capture. + /// The slice of the input which was captured, if there was a capture. + /// + /// If nothing was captured, `substring` is `nil`. public var substring: Substring? { range.map { input[$0] } } - /// The captured value, `nil` for no-capture. + /// The captured value, if there was a capture. + /// + /// If nothing was captured, `value` is `nil`. public var value: Any? { representation.value(forInput: input) } + /// The type of this capture. public var type: Any.Type { representation.type } - /// The name of this capture, if it has one, otherwise `nil`. + /// The name of this capture, if the capture is named. + /// + /// If the capture is unnamed, `name` is `nil`. public var name: String? { representation.name } @@ -110,7 +123,12 @@ extension AnyRegexOutput: RandomAccessCollection { @available(SwiftStdlib 5.7, *) extension AnyRegexOutput { - /// Access a capture by name. Returns `nil` if no capture with that name was present in the Regex. + /// Accesses the capture with the specified name, if a capture with that name + /// exists. + /// + /// - Parameter name: The name of the capture to access. + /// - Returns: An element providing information about the capture, if there is + /// a capture named `name`; otherwise, `nil`. public subscript(name: String) -> Element? { first { $0.name == name @@ -122,12 +140,17 @@ extension AnyRegexOutput { extension Regex.Match where Output == AnyRegexOutput { /// Accesses the whole match using the `.0` syntax. public subscript( - dynamicMember keyPath: KeyPath<(Substring, _doNotUse: ()), Substring> + dynamicMember _keyPath: KeyPath<(Substring, _doNotUse: ()), Substring> ) -> Substring { anyRegexOutput.input[range] } - /// Access a capture by name. Returns `nil` if there's no capture with that name. + /// Accesses the capture with the specified name, if a capture with that name + /// exists. + /// + /// - Parameter name: The name of the capture to access. + /// - Returns: An element providing information about the capture, if there is + /// a capture named `name`; otherwise, `nil`. public subscript(name: String) -> AnyRegexOutput.Element? { anyRegexOutput.first { $0.name == name @@ -139,9 +162,22 @@ extension Regex.Match where Output == AnyRegexOutput { @available(SwiftStdlib 5.7, *) extension Regex where Output == AnyRegexOutput { - /// Parses and compiles a regular expression, resulting in a type-erased capture list. + /// Creates a regular expression from the given string, using a dynamic + /// capture list. + /// + /// Use this initializer to create a `Regex` instance from a regular + /// expression that you have stored in `pattern`. + /// + /// let simpleDigits = try Regex("[0-9]+") + /// + /// This initializer throws an error if `pattern` uses invalid regular + /// expression syntax. + /// + /// The output type of the new `Regex` is the dynamic ``AnyRegexOutput``. + /// If you know the capture structure of `pattern` ahead of time, use the + /// ``init(_:as:)`` initializer instead. /// - /// - Parameter pattern: The regular expression. + /// - Parameter pattern: A string with regular expression syntax. public init(_ pattern: String) throws { self.init(ast: try parse(pattern, .traditional)) } @@ -153,13 +189,32 @@ extension Regex where Output == AnyRegexOutput { @available(SwiftStdlib 5.7, *) extension Regex { - /// Parses and compiles a regular expression. + /// Creates a regular expression from the given string, using the specified + /// capture type. /// - /// - Parameter pattern: The regular expression. - /// - Parameter as: The desired type for the output. + /// You can use this initializer to create a `Regex` instance from a regular + /// expression that you have stored in `pattern` when you know the capture + /// structure of the regular expression in advance. + /// + /// In this example, the regular expression includes two parenthesized + /// capture groups, so the capture type is `(Substring, Substring, Substring)`. + /// The first substring in the tuple represents the entire match, while the + /// second and third substrings represent the first and second capture group, + /// respectively. + /// + /// let keyAndValue = try Regex("(.+): (.+)", as: (Substring, Substring, Substring).self) + /// + /// This initializer throws an error if `pattern` uses invalid regular + /// expression syntax, or if `outputType` does not match the capture + /// structure declared by `pattern`. If you don't know the capture structure + /// in advance, use the ``init(_:)`` initializer instead. + /// + /// - Parameters: + /// - pattern: A string with regular expression syntax. + /// - outputType: The desired type for the output captures. public init( _ pattern: String, - as: Output.Type = Output.self + as outputType: Output.Type = Output.self ) throws { let regex = Regex(ast: try parse(pattern, .traditional)) @@ -175,13 +230,40 @@ extension Regex { self = regex } - /// Produces a regex that matches `verbatim` exactly, as though every - /// metacharacter in it was escaped. - public init(verbatim: String) { - self.init(node: .quotedLiteral(verbatim)) + /// Creates a regular expression that matches the given string exactly, as + /// though every metacharacter in it was escaped. + /// + /// This example creates a regular expression that matches the string + /// `"(adj)"`, including the parentheses. Although parentheses are regular + /// expression metacharacters, they do not need escaping in the string passed + /// as `verbatimString`. + /// + /// let adjectiveDesignator = Regex(verbatim: "(adj.)") + /// + /// print("awesome (adj.)".contains(adjectiveDesignator)) + /// // Prints "true" + /// print("apple (n.)".contains(adjectiveDesignator)) + /// // Prints "false" + /// + /// - Parameter verbatimString: A string to convert into a regular expression + /// exactly, escaping any metacharacters. + public init(verbatim verbatimString: String) { + self.init(node: .quotedLiteral(verbatimString)) } - /// Returns whether a named-capture with `name` exists + /// Returns a Boolean value indicating whether a named capture with the given + /// name exists. + /// + /// This example shows a regular expression that includes capture groups + /// named `key` and `value`: + /// + /// let regex = try Regex("(?'key'.+?): (?'value'.+)") + /// regex.contains(captureNamed: "key") // true + /// regex.contains(captureNamed: "VALUE") // false + /// regex.contains(captureNamed: "1") // false + /// + /// - Parameter name: The name to look for among the regular expression's + /// capture groups. Capture group names are case sensitive. public func contains(captureNamed name: String) -> Bool { program.tree.captureList.captures.contains(where: { $0.name == name @@ -193,10 +275,14 @@ extension Regex { @available(SwiftStdlib 5.7, *) extension Regex where Output == AnyRegexOutput { - /// Creates a type-erased regex from an existing regex. + /// Creates a regular expression with a dynamic capture list from the given + /// regular expression. /// - /// Use this initializer to fit a regex with strongly-typed captures into the - /// use site of a type-erased regex, i.e. one that was created from a string. + /// You can use this initializer to convert a `Regex` with strongly-typed + /// captures into a `Regex` with `AnyRegexOutput` as its output type. + /// + /// - Parameter regex: A regular expression to convert to use a dynamic + /// capture list. public init(_ regex: Regex) { self.init(node: regex.root) } @@ -204,10 +290,15 @@ extension Regex where Output == AnyRegexOutput { @available(SwiftStdlib 5.7, *) extension Regex.Match where Output == AnyRegexOutput { - /// Creates a type-erased regex match from an existing match. + /// Creates a regular expression match with a dynamic capture list from the + /// given match. + /// + /// You can use this initializer to convert a `Regex.Match` with + /// strongly-typed captures into a match with the type-eraser `AnyRegexOutput` + /// as its output type. /// - /// Use this initializer to fit a regex match with strongly-typed captures into the - /// use site of a type-erased regex match. + /// - Parameter match: A regular expression match to convert to a match with + /// type-erased captures. public init(_ match: Regex.Match) { self.init( anyRegexOutput: match.anyRegexOutput, @@ -218,16 +309,29 @@ extension Regex.Match where Output == AnyRegexOutput { @available(SwiftStdlib 5.7, *) extension Regex { - /// Creates a strongly-typed regex from a type-erased regex. + /// Creates a regular expression with a strongly-typed capture list from the + /// given regular expression. + /// + /// You can use this initializer to convert a regular expression with a + /// dynamic capture list to one with a strongly-typed capture list. If the + /// type you provide as `outputType` doesn't match the capture structure of + /// `regex`, the initializer returns `nil`. /// - /// Use this initializer to create a strongly-typed regex from - /// one that was created from a string. Returns `nil` if the types - /// don't match. + /// let dynamicRegex = try Regex("(.+?): (.+)") + /// if let stronglyTypedRegex = Regex(dynamicRegex, as: (Substring, Substring, Substring).self) { + /// print("Converted properly") + /// } + /// // Prints "Converted properly" + /// + /// - Parameters: + /// - regex: A regular expression to convert to use a strongly-typed capture + /// list. + /// - outputType: The capture structure to use. public init?( - _ erased: Regex, - as: Output.Type = Output.self + _ regex: Regex, + as outputType: Output.Type = Output.self ) { - self.init(node: erased.root) + self.init(node: regex.root) guard _verifyType().0 else { return nil diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index ba40f4f90..5940fd500 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -12,19 +12,70 @@ @_implementationOnly import _RegexParser /// A type that represents a regular expression. +/// +/// You can use types that conform to `RegexComponent` as parameters to string +/// searching operations and inside `RegexBuilder` closures. @available(SwiftStdlib 5.7, *) public protocol RegexComponent { + /// The output type for this regular expression. + /// + /// A `Regex` instance's output type depends on whether the `Regex` has + /// captures and how it is created. + /// + /// - A `Regex` created from a string using the ``init(_:)`` initializer + /// has an output type of ``AnyRegexOutput``, whether it has captures or + /// not. + /// - A `Regex` without captures created from a regex literal, the + /// ``init(_:as:)`` initializer, or a `RegexBuilder` closure has a + /// `Substring` output type, where the substring is the portion of the + /// string that was matched. + /// - A `Regex` with captures created from a regex literal or the + /// ``init(_:as:)`` initializer has a tuple of substrings as its output + /// type. The first component of the tuple is the full portion of the string + /// that was matched, with the remaining components holding the captures. associatedtype RegexOutput + + /// The regular expression represented by this component. var regex: Regex { get } } /// A regular expression. /// -/// let regex = try Regex("a(.*)b") -/// let match = "cbaxb".firstMatch(of: regex) -/// print(match.0) // "axb" -/// print(match.1) // "x" +/// Regular expressions are a concise way of describing a pattern, which can +/// help you match or extract portions of a string. You can create a `Regex` +/// instance using regular expression syntax, either in a regex literal or a +/// string. +/// +/// // 'keyAndValue' is created using a regex literal +/// let keyAndValue = /(.+?): (.+)/ +/// // 'simpleDigits' is created from a pattern in a string +/// let simpleDigits = try Regex("[0-9]+") +/// +/// You can use a `Regex` to search for a pattern in a string or substring. +/// Call `contains(_:)` to check for the presence of a pattern, or +/// `firstMatch(of:)` or `matches(of:)` to find matches. +/// +/// let setting = "color: 161 103 230" +/// if setting.contains(simpleDigits) { +/// print("'\(setting)' contains some digits.") +/// } +/// // Prints "'color: 161 103 230' contains some digits." +/// +/// When you find a match, the resulting ``Match`` type includes an +/// ``Match/output`` property that contains the matched substring along with +/// any captures: +/// +/// if let match = setting.firstMatch(of: keyAndValue) { +/// print("Key: \(match.1)") +/// print("Value: \(match.2)") +/// } +/// // Key: color +/// // Value: 161 103 230 /// +/// When you import the `RegexBuilder` module, you can also create `Regex` +/// instances using a clear and flexible declarative syntax. Using this +/// style, you can combine, capture, and transform regexes, `RegexBuilder` +/// types, and custom parsers. @available(SwiftStdlib 5.7, *) public struct Regex: RegexComponent { let program: Program @@ -64,8 +115,8 @@ public struct Regex: RegexComponent { @available(SwiftStdlib 5.7, *) extension Regex { @available(*, deprecated, renamed: "init(verbatim:)") - public init(quoting string: String) { - self.init(node: .quotedLiteral(string)) + public init(quoting _string: String) { + self.init(node: .quotedLiteral(_string)) } } diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 0fb4e0eb8..e5e899ced 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -11,7 +11,7 @@ @available(SwiftStdlib 5.7, *) extension Regex { - /// The result of matching a regex against a string. + /// The result of matching a regular expression against a string. /// /// A `Match` forwards API to the `Output` generic parameter, /// providing direct access to captures. @@ -56,11 +56,12 @@ extension Regex.Match { /// Accesses a capture using the `.0` syntax, even when the match isn't a tuple. @_disfavoredOverload public subscript( - dynamicMember keyPath: KeyPath<(Output, _doNotUse: ()), Output> + dynamicMember _keyPath: KeyPath<(Output, _doNotUse: ()), Output> ) -> Output { output } + // Helper for `subscript(_: Reference)`, defined in RegexBuilder. @_spi(RegexBuilder) public subscript(_ id: ReferenceID) -> Capture { guard let element = anyRegexOutput.first( @@ -76,52 +77,187 @@ extension Regex.Match { @available(SwiftStdlib 5.7, *) extension Regex { - /// Matches a string in its entirety. + /// Returns a match if this regex matches the given string in its entirety. /// - /// - Parameter s: The string to match this regular expression against. - /// - Returns: The match, or `nil` if no match was found. - public func wholeMatch(in s: String) throws -> Regex.Match? { - try _match(s, in: s.startIndex.. Regex.Match? { + try _match(string, in: string.startIndex.. Regex.Match? { - try _match(s, in: s.startIndex.. Regex.Match? { + try _match(string, in: string.startIndex.. Regex.Match? { - try _firstMatch(s, in: s.startIndex.. Regex.Match? { + try _firstMatch(string, in: string.startIndex.. Regex.Match? { - try _match(s.base, in: s.startIndex.. Regex.Match? { + try _match(string.base, in: string.startIndex.. Regex.Match? { - try _match(s.base, in: s.startIndex.. Regex.Match? { + try _match(string.base, in: string.startIndex.. Regex.Match? { - try _firstMatch(s.base, in: s.startIndex.. Regex.Match? { + try _firstMatch(string.base, in: string.startIndex..( - of r: R + of regex: R ) -> Regex.Match? { - try? r.regex.wholeMatch(in: self[...]) + try? regex.regex.wholeMatch(in: self[...]) } - /// Checks for a match against the string, starting at its beginning. + /// Returns a match if this string is matched by the given regex at its start. /// - /// - Parameter r: The regular expression being matched. - /// - Returns: The match, or `nil` if no match was found. + /// - Parameter regex: The regular expression to match. + /// - Returns: The match, if one is found. If there is no match, or a + /// transformation in `regex` throws an error, this method returns `nil`. public func prefixMatch( - of r: R + of regex: R ) -> Regex.Match? { - try? r.regex.prefixMatch(in: self[...]) + try? regex.regex.prefixMatch(in: self[...]) } } diff --git a/Sources/_StringProcessing/Regex/Options.swift b/Sources/_StringProcessing/Regex/Options.swift index 368a5b634..1e58e78d5 100644 --- a/Sources/_StringProcessing/Regex/Options.swift +++ b/Sources/_StringProcessing/Regex/Options.swift @@ -83,8 +83,8 @@ extension Regex { /// /// This method corresponds to applying the `m` option in regex syntax. For /// this behavior in the `RegexBuilder` syntax, see - /// ``Anchor.startOfLine``, ``Anchor.endOfLine``, ``Anchor.startOfSubject``, - /// and ``Anchor.endOfSubject``. + /// `Anchor.startOfLine`, `Anchor.endOfLine`, `Anchor.startOfSubject`, + /// and `Anchor.endOfSubject`. /// /// - Parameter matchLineEndings: A Boolean value indicating whether `^` and /// `$` should match the start and end of lines, respectively. @@ -161,8 +161,13 @@ extension Regex { } } -@available(SwiftStdlib 5.7, *) /// A semantic level to use during regex matching. +/// +/// The semantic level determines whether a regex matches with the same +/// character-based semantics as string comparisons or by matching individual +/// Unicode scalar values. See ``Regex/matchingSemantics(_:)`` for more about +/// changing the semantic level for all or part of a regex. +@available(SwiftStdlib 5.7, *) public struct RegexSemanticLevel: Hashable { internal enum Representation { case graphemeCluster @@ -181,15 +186,18 @@ public struct RegexSemanticLevel: Hashable { /// Match at the Unicode scalar level. /// - /// At this semantic level, the string's `UnicodeScalarView` is used for matching, - /// and each matched element is a `UnicodeScalar` value. + /// At this semantic level, the string's `UnicodeScalarView` is used for + /// matching, and each matched element is a `UnicodeScalar` value. public static var unicodeScalar: RegexSemanticLevel { .init(base: .unicodeScalar) } } -@available(SwiftStdlib 5.7, *) /// A word boundary algorithm to use during regex matching. +/// +/// See ``Regex/wordBoundaryKind(_:)`` for information about specifying the +/// word boundary kind for all or part of a regex. +@available(SwiftStdlib 5.7, *) public struct RegexWordBoundaryKind: Hashable { internal enum Representation { case unicodeLevel1 @@ -221,6 +229,9 @@ public struct RegexWordBoundaryKind: Hashable { } /// Specifies how much to attempt to match when using a quantifier. +/// +/// See ``Regex/repetitionBehavior(_:)`` for more about specifying the default +/// matching behavior for all or part of a regex. @available(SwiftStdlib 5.7, *) public struct RegexRepetitionBehavior: Hashable { internal enum Kind { diff --git a/Tests/DocumentationTests/RegexBuilderTests.swift b/Tests/DocumentationTests/RegexBuilderTests.swift new file mode 100644 index 000000000..835f6e333 --- /dev/null +++ b/Tests/DocumentationTests/RegexBuilderTests.swift @@ -0,0 +1,202 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// +// +// Tests for the code samples in the RegexBuilder documentation. +// +//===----------------------------------------------------------------------===// + +import XCTest +import _StringProcessing +import RegexBuilder + +class RegexBuilderTests: XCTestCase {} + +extension RegexBuilderTests { + func testCharacterClass_inverted() throws { + let validCharacters = CharacterClass("a"..."z", .anyOf("-_")) + let invalidCharacters = validCharacters.inverted + + let username = "user123" + if username.contains(invalidCharacters) { + print("Invalid username: '\(username)'") + } + // Prints "Invalid username: 'user123'" + + XCTAssertTrue(username.contains(invalidCharacters)) + } + + func testCharacterClass_anyOf() { + let regex1 = /[abcd]+/ + let regex2 = OneOrMore(.anyOf("abcd")) + + // syntax/compilation test + } + + func testChoiceOf() throws { + let regex = Regex { + ChoiceOf { + "CREDIT" + "DEBIT" + } + } + let match = try regex.prefixMatch(in: "DEBIT 04032020 Payroll $69.73") + print(match?.0 as Any) + // Prints "DEBIT" + + XCTAssertEqual(match?.0, "DEBIT") + } + + func testReference() throws { + let kindRef = Reference(Substring.self) + let kindRegex = ChoiceOf { + "CREDIT" + "DEBIT" + } + + let transactionRegex = Regex { + Anchor.startOfLine + Capture(kindRegex, as: kindRef) + OneOrMore(.anyNonNewline) + kindRef + Anchor.endOfLine + } + + let validTransaction = "CREDIT 109912311421 Payroll $69.73 CREDIT" + let invalidTransaction = "DEBIT 00522142123 Expense $5.17 CREDIT" + + print(validTransaction.contains(transactionRegex)) + // Prints "true" + print(invalidTransaction.contains(transactionRegex)) + // Prints "false" + + if let match = validTransaction.firstMatch(of: transactionRegex) { + print(match[kindRef]) + } + // Prints "CREDIT" + + struct Transaction: Equatable { + var id: UInt64 + } + let transactionRef = Reference(Transaction.self) + + let transactionIDRegex = Regex { + Capture(kindRegex, as: kindRef) + OneOrMore(.whitespace) + TryCapture(as: transactionRef) { + OneOrMore(.digit) + } transform: { str in + UInt64(str).map(Transaction.init(id:)) + } + OneOrMore(.anyNonNewline) + kindRef + Anchor.endOfLine + } + + if let match = validTransaction.firstMatch(of: transactionIDRegex) { + print(match[transactionRef]) + } + // Prints "Transaction(id: 109912311421)" + + XCTAssertTrue(validTransaction.contains(transactionRegex)) + XCTAssertFalse(invalidTransaction.contains(transactionRegex)) + + XCTAssertEqual(validTransaction.firstMatch(of: transactionRegex)?[kindRef], "CREDIT") + + XCTAssertEqual( + validTransaction.firstMatch(of: transactionIDRegex)?[transactionRef], + Transaction(id: 109912311421)) + } + + func testCapture() throws { + let transactions = """ + CREDIT 109912311421 Payroll $69.73 + CREDIT 105912031123 Travel $121.54 + DEBIT 107733291022 Refund $8.42 + """ + + let regex = Regex { + "$" + Capture { + OneOrMore(.digit) + "." + Repeat(.digit, count: 2) + } + Anchor.endOfLine + } + + // The type of each match's output is `(Substring, Substring)`. + for match in transactions.matches(of: regex) { + print("Transaction amount: \(match.1)") + } + // Prints "Transaction amount: 69.73" + // Prints "Transaction amount: 121.54" + // Prints "Transaction amount: 8.42" + + let doubleValueRegex = Regex { + "$" + Capture { + OneOrMore(.digit) + "." + Repeat(.digit, count: 2) + } transform: { Double($0)! } + Anchor.endOfLine + } + + // The type of each match's output is `(Substring, Double)`. + for match in transactions.matches(of: doubleValueRegex) { + if match.1 >= 100.0 { + print("Large amount: \(match.1)") + } + } + // Prints "Large amount: 121.54" + + let matchCaptures = transactions.matches(of: regex).map(\.1) + XCTAssertEqual(matchCaptures, ["69.73", "121.54", "8.42"]) + + let doubleValues = transactions.matches(of: doubleValueRegex).map(\.1) + XCTAssertEqual(doubleValues, [69.73, 121.54, 8.42]) + } + + func testTryCapture() throws { + let transactions = """ + CREDIT 109912311421 Payroll $69.73 + CREDIT 105912031123 Travel $121.54 + DEBIT 107733291022 Refund $8.42 + """ + let transactionLimit = 100.0 + + let regex = Regex { + "$" + TryCapture { + OneOrMore(.digit) + "." + Repeat(.digit, count: 2) + } transform: { str -> Double? in + let value = Double(str)! + if value > transactionLimit { + return value + } + return nil + } + Anchor.endOfLine + } + + // The type of each match's output is `(Substring, Double)`. + for match in transactions.matches(of: regex) { + print("Transaction amount: \(match.1)") + } + // Prints "Transaction amount: 121.54" + + let matches = transactions.matches(of: regex) + XCTAssertEqual(matches.count, 1) + XCTAssertEqual(matches[0].1, 121.54) + } +} diff --git a/Tests/DocumentationTests/RegexTests.swift b/Tests/DocumentationTests/RegexTests.swift new file mode 100644 index 000000000..ba3910245 --- /dev/null +++ b/Tests/DocumentationTests/RegexTests.swift @@ -0,0 +1,149 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// +// +// Tests for the code samples in the Regex documentation. +// +//===----------------------------------------------------------------------===// + +import XCTest +import _StringProcessing + +class RegexTests: XCTestCase {} + +extension RegexTests { + func testRegex() throws { + // 'keyAndValue' is created using a regex literal + let keyAndValue = /(.+?): (.+)/ + // 'simpleDigits' is created from a pattern in a string + let simpleDigits = try Regex("[0-9]+") + + let setting = "color: 161 103 230" + if setting.contains(simpleDigits) { + print("'\(setting)' contains some digits.") + } + // Prints "'color: 161 103 230' contains some digits." + + if let match = setting.firstMatch(of: keyAndValue) { + print("Key: \(match.1)") + print("Value: \(match.2)") + } + // Key: color + // Value: 161 103 230 + + XCTAssertTrue(setting.contains(simpleDigits)) + + let match = try XCTUnwrap(setting.firstMatch(of: keyAndValue)) + XCTAssertEqual(match.1, "color") + XCTAssertEqual(match.2, "161 103 230") + } + + func testRegex_init() throws { + let simpleDigits = try Regex("[0-9]+") + + // shouldn't throw + } + + func testRegex_initStringAs() throws { + let keyAndValue = try Regex("(.+): (.+)", as: (Substring, Substring, Substring).self) + + // shouldn't throw + } + + func testRegex_initRegexAs() throws { + let dynamicRegex = try Regex("(.+?): (.+)") + if let stronglyTypedRegex = Regex(dynamicRegex, as: (Substring, Substring, Substring).self) { + print("Converted properly") + } + // Prints "Converted properly" + + XCTAssertNotNil(Regex(dynamicRegex, as: (Substring, Substring, Substring).self)) + } + + func testRegex_initVerbatim() throws { + let adjectiveDesignator = Regex(verbatim: "(adj.)") + + print("awesome (adj.)".contains(adjectiveDesignator)) + // Prints "true" + print("apple (n.)".contains(adjectiveDesignator)) + // Prints "false" + + XCTAssertTrue("awesome (adj.)".contains(adjectiveDesignator)) + XCTAssertFalse("apple (n.)".contains(adjectiveDesignator)) + } + + func testRegex_containsCapture() throws { + let regex = try Regex("(?'key'.+?): (?'value'.+)") + regex.contains(captureNamed: "key") // true + regex.contains(captureNamed: "VALUE") // false + regex.contains(captureNamed: "1") // false + + XCTAssertTrue(regex.contains(captureNamed: "key")) + XCTAssertFalse(regex.contains(captureNamed: "VALUE")) + XCTAssertFalse(regex.contains(captureNamed: "1")) + } +} + +extension RegexTests { + func testRegex_wholeMatchIn() throws { + let digits = /[0-9]+/ + + if let digitsMatch = try digits.wholeMatch(in: "2022") { + print(digitsMatch.0) + } else { + print("No match.") + } + // Prints "2022" + + if let digitsMatch = try digits.wholeMatch(in: "The year is 2022.") { + print(digitsMatch.0) + } else { + print("No match.") + } + // Prints "No match." + + XCTAssertEqual(try digits.wholeMatch(in: "2022")?.0, "2022") + XCTAssertNil(try digits.wholeMatch(in: "The year is 2022.")) + } + + func testRegex_prefixMatchIn() throws { + let titleCaseWord = /[A-Z][A-Za-z]+/ + + if let wordMatch = try titleCaseWord.prefixMatch(in: "Searching in a Regex") { + print(wordMatch.0) + } else { + print("No match.") + } + // Prints "Searching" + + if let wordMatch = try titleCaseWord.prefixMatch(in: "title case word at the End") { + print(wordMatch.0) + } else { + print("No match.") + } + // Prints "No match." + + XCTAssertEqual(try titleCaseWord.prefixMatch(in: "Searching in a Regex")?.0, "Searching") + XCTAssertNil(try titleCaseWord.prefixMatch(in: "title case word at the End")) + } + + func testRegex_firstMatchIn() throws { + let digits = /[0-9]+/ + + if let digitsMatch = try digits.firstMatch(in: "The year is 2022; last year was 2021.") { + print(digitsMatch.0) + } else { + print("No match.") + } + // Prints "2022" + + XCTAssertEqual(try digits.firstMatch(in: "The year is 2022; last year was 2021.")?.0, "2022") + } +} From c34cea5f8fbfb5cea9df626df61ede25d0d05512 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 15 Dec 2022 23:52:37 -0600 Subject: [PATCH 08/34] Set availability for inverted character class test (#621) This feature depends on running with a Swift 5.7 stdlib, and fails when that isn't available. --- Package.swift | 2 +- Tests/DocumentationTests/RegexBuilderTests.swift | 5 +++++ Tests/DocumentationTests/RegexTests.swift | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index baeea543f..b30c402c4 100644 --- a/Package.swift +++ b/Package.swift @@ -93,7 +93,7 @@ let package = Package( name: "DocumentationTests", dependencies: ["_StringProcessing", "RegexBuilder"], swiftSettings: [ - .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]), + availabilityDefinition, .unsafeFlags(["-enable-bare-slash-regex"]), ]), diff --git a/Tests/DocumentationTests/RegexBuilderTests.swift b/Tests/DocumentationTests/RegexBuilderTests.swift index 835f6e333..d0ae36e01 100644 --- a/Tests/DocumentationTests/RegexBuilderTests.swift +++ b/Tests/DocumentationTests/RegexBuilderTests.swift @@ -19,8 +19,13 @@ import RegexBuilder class RegexBuilderTests: XCTestCase {} +@available(SwiftStdlib 5.7, *) extension RegexBuilderTests { func testCharacterClass_inverted() throws { + // `CharacterClass` depends on some standard library SPI that is only + // available in >= macOS 13. The warning for the next line is spurious. + guard #available(macOS 13, *) else { return } + let validCharacters = CharacterClass("a"..."z", .anyOf("-_")) let invalidCharacters = validCharacters.inverted diff --git a/Tests/DocumentationTests/RegexTests.swift b/Tests/DocumentationTests/RegexTests.swift index ba3910245..1394839c9 100644 --- a/Tests/DocumentationTests/RegexTests.swift +++ b/Tests/DocumentationTests/RegexTests.swift @@ -18,6 +18,7 @@ import _StringProcessing class RegexTests: XCTestCase {} +@available(SwiftStdlib 5.7, *) extension RegexTests { func testRegex() throws { // 'keyAndValue' is created using a regex literal @@ -91,6 +92,7 @@ extension RegexTests { } } +@available(SwiftStdlib 5.7, *) extension RegexTests { func testRegex_wholeMatchIn() throws { let digits = /[0-9]+/ From 3a3dc7a7d761b7885e5c25df247f2c4c49cb6fcc Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 31 Jan 2023 19:17:45 -0600 Subject: [PATCH 09/34] Add type annotations in RegexBuilder tests These changes work around a change to the way result builders are compiled that removes the ability for result builder closure outputs to affect the overload resolution elsewhere in an expression. Workarounds for rdar://104881395 and rdar://104645543 --- Tests/RegexBuilderTests/CustomTests.swift | 18 +++++++++--------- Tests/RegexBuilderTests/MotivationTests.swift | 12 ++++++------ Tests/RegexBuilderTests/RegexDSLTests.swift | 10 +++++----- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index bc71f2363..d34b5689f 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -183,7 +183,7 @@ class CustomRegexComponentTests: XCTestCase { // tests. func testCustomRegexComponents() throws { customTest( - Regex { + Regex { Numbler() Asciibbler() }, @@ -194,7 +194,7 @@ class CustomRegexComponentTests: XCTestCase { ("t4", .match, nil)) customTest( - Regex { + Regex { OneOrMore { Numbler() } }, ("ab123c", .firstMatch, "123"), @@ -425,7 +425,7 @@ class CustomRegexComponentTests: XCTestCase { ) customTest( - Regex { + Regex { CurrencyParser() }, ("USD", .usd, nil), @@ -437,7 +437,7 @@ class CustomRegexComponentTests: XCTestCase { // No capture, two errors customTest( - Regex { + Regex { IntParser() " " IntParser() @@ -449,7 +449,7 @@ class CustomRegexComponentTests: XCTestCase { ) customTest( - Regex { + Regex { CurrencyParser() IntParser() }, @@ -462,7 +462,7 @@ class CustomRegexComponentTests: XCTestCase { // One capture, two errors: One error is thrown from inside a capture, // while the other one is thrown from outside customTest( - Regex { + Regex<(Substring, CurrencyParser.Currency)> { Capture { CurrencyParser() } IntParser() }, @@ -473,7 +473,7 @@ class CustomRegexComponentTests: XCTestCase { ) customTest( - Regex { + Regex<(Substring, Int)> { CurrencyParser() Capture { IntParser() } }, @@ -485,7 +485,7 @@ class CustomRegexComponentTests: XCTestCase { // One capture, two errors: Both errors are thrown from inside the capture customTest( - Regex { + Regex<(Substring, Substring)> { Capture { CurrencyParser() IntParser() @@ -499,7 +499,7 @@ class CustomRegexComponentTests: XCTestCase { // Two captures, two errors: Different erros are thrown from inside captures customTest( - Regex { + Regex<(Substring, CurrencyParser.Currency, Int)> { Capture(CurrencyParser()) Capture(IntParser()) }, diff --git a/Tests/RegexBuilderTests/MotivationTests.swift b/Tests/RegexBuilderTests/MotivationTests.swift index 7dd4c77e4..f72486610 100644 --- a/Tests/RegexBuilderTests/MotivationTests.swift +++ b/Tests/RegexBuilderTests/MotivationTests.swift @@ -309,8 +309,8 @@ extension RegexDSLTests { "CREDIT" "DEBIT" } - } transform: { - TransactionKind(rawValue: String($0)) + } transform: { (s: Substring) in + TransactionKind(rawValue: String(s)) } OneOrMore(.whitespace) @@ -322,8 +322,8 @@ extension RegexDSLTests { Repeat(.digit, count: 2) Repeat(.digit, count: 2) Repeat(.digit, count: 4) - } transform: { - Date(mmddyyyy: String($0)) + } transform: { (s: Substring) in + Date(mmddyyyy: String(s)) } OneOrMore(.whitespace) @@ -345,8 +345,8 @@ extension RegexDSLTests { OneOrMore(.digit) "." Repeat(.digit, count: 2) - } transform: { - Double($0) + } transform: { (s: Substring) in + Double(s) } } diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index e25f2df05..8b7611536 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -1253,8 +1253,8 @@ class RegexDSLTests: XCTestCase { TryCapture(as: b) { "#" OneOrMore(.digit) - } transform: { - Int($0.dropFirst()) + } transform: { (s: Substring) in + Int(s.dropFirst()) } } a @@ -1271,14 +1271,14 @@ class RegexDSLTests: XCTestCase { do { let a = Reference(Substring.self) let b = Reference(Int.self) - let regex = Regex { + let regex = Regex<(Substring, Substring, Int?, Int?, Substring?)> { Capture("abc", as: a) ZeroOrMore { TryCapture(as: b) { "#" OneOrMore(.digit) - } transform: { - Int($0.dropFirst()) + } transform: { (s: Substring) -> Int? in + Int(s.dropFirst()) } } a From 6c4f2919cd8c9dd24bb1b6897c10ce4870a0de3c Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 1 Feb 2023 12:53:58 -0600 Subject: [PATCH 10/34] Workaround for fileprivate array issue A recent compiler change results in fileprivate arrays sometimes not keeping their buffers around long enough. This change avoids that issue by removing the fileprivate annotations from the affected type. --- Sources/_StringProcessing/MatchingOptions.swift | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Sources/_StringProcessing/MatchingOptions.swift b/Sources/_StringProcessing/MatchingOptions.swift index d511c9f7c..60cc7d0de 100644 --- a/Sources/_StringProcessing/MatchingOptions.swift +++ b/Sources/_StringProcessing/MatchingOptions.swift @@ -14,7 +14,9 @@ /// A type that represents the current state of regex matching options, with /// stack-based scoping. struct MatchingOptions { - fileprivate var stack: [Representation] + // FIXME: Workaround for rdar://104923020 + // fileprivate + var stack: [Representation] fileprivate func _invariantCheck() { assert(!stack.isEmpty, "Unbalanced call to endScope") @@ -125,7 +127,9 @@ extension MatchingOptions { // MARK: - Implementation extension MatchingOptions { /// An option that changes the behavior of a regular expression. - fileprivate enum Option: Int { + // FIXME: Workaround for rdar://104923020 + // fileprivate + enum Option: Int { // PCRE options case caseInsensitive case allowDuplicateGroupNames @@ -212,7 +216,9 @@ extension MatchingOptions { extension MatchingOptions { /// A set of matching options. - fileprivate struct Representation: OptionSet, RawRepresentable { + // FIXME: Workaround for rdar://104923020 + // fileprivate + struct Representation: OptionSet, RawRepresentable { var rawValue: UInt32 /// Returns `true` if the option denoted by `kind` is a member of this set. From 6a4077fc17dcdb8eee3682d79351fbfc0d2262a6 Mon Sep 17 00:00:00 2001 From: David Ewing Date: Wed, 1 Feb 2023 13:52:56 -0700 Subject: [PATCH 11/34] Fix an issue where named character classes weren't getting converted in the result builder. --- .../_StringProcessing/PrintAsPattern.swift | 8 +++++ Tests/RegexTests/RenderDSLTests.swift | 36 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 953df6882..61eb54ca8 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -518,6 +518,14 @@ extension PrettyPrinter { } else { output(base.0) } + + case let .characterClass(cc): + if wrap { + output("One(\(cc._patternBase))") + } else { + output(cc._patternBase) + } + default: print(" // TODO: Atom \(a)") } diff --git a/Tests/RegexTests/RenderDSLTests.swift b/Tests/RegexTests/RenderDSLTests.swift index c38ff0663..fbfbee616 100644 --- a/Tests/RegexTests/RenderDSLTests.swift +++ b/Tests/RegexTests/RenderDSLTests.swift @@ -276,4 +276,40 @@ extension RenderDSLTests { } """#) } + + func testCharacterClass() throws { + try testConversion(#"[abc]+"#, #""" + Regex { + OneOrMore(.anyOf("abc")) + } + """#) + + try testConversion(#"[[:whitespace:]]"#, #""" + Regex { + One(.whitespace) + } + """#) + + try testConversion(#"[\b\w]+"#, #""" + Regex { + OneOrMore { + CharacterClass( + .anyOf("\u{8}"), + .word + ) + } + } + """#) + + try testConversion(#"[abc\sd]+"#, #""" + Regex { + OneOrMore { + CharacterClass( + .anyOf("abcd"), + .whitespace + ) + } + } + """#) + } } From 2a78475af215cc2ae3de7d96f4c72db0ea02f21f Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 8 Feb 2023 09:28:46 -0800 Subject: [PATCH 12/34] Stop at end of search string in TwoWaySearcher (#631) When searching for a substring that doesn't exist, it was possible for TwoWaySearcher to advance beyond the end of the search string, causing a crash. This change adds a `limitedBy:` parameter to that index movement, avoiding the invalid movement. Fixes rdar://105154010 --- .../Algorithms/Searchers/TwoWaySearcher.swift | 5 ++++- Tests/RegexTests/AlgorithmsTests.swift | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift index c3537d415..2428f89cd 100644 --- a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift +++ b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift @@ -133,7 +133,10 @@ extension TwoWaySearcher: CollectionSearcher { searched.formIndex(before: &lIndex) if pattern[i] != searched[lIndex] { - searched.formIndex(&state.criticalIndex, offsetBy: period) + _ = searched.formIndex( + &state.criticalIndex, + offsetBy: period, + limitedBy: searched.endIndex) if periodIsExact { state.memory = (pattern.count - period, end) } return nil } diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index 71eff7c6d..8ff3ad607 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -174,6 +174,16 @@ class AlgorithmTests: XCTestCase { expectRanges("ababacabababa", "abababa", [6..<13]) expectRanges("ababacabababa", "aba", [0..<3, 6..<9, 10..<13]) } + + // rdar://105154010 + func testFirstRangeMissingCrash() { + let str = "%2$@ %#@AROUND_TIME@" + let target = "%@" + XCTAssertNil(str.firstRange(of: target)) + XCTAssertNil(str.dropFirst().dropLast().firstRange(of: target)) + XCTAssertNil(str.dropFirst().dropLast().firstRange(of: target[...])) + XCTAssertNil(str.firstRange(of: target[...])) + } func testRegexSplit() { func expectSplit( From d5a6cecb151e68dfd08dec9e0e3c2bf7b1d7644e Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 8 Feb 2023 11:06:01 -0800 Subject: [PATCH 13/34] Correct misspelling in DSL renderer (#627) vertial -> vertical rdar://104602317 --- .../_StringProcessing/PrintAsPattern.swift | 2 +- Tests/RegexTests/RenderDSLTests.swift | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 61eb54ca8..234efd3c5 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -778,7 +778,7 @@ extension DSLTree.Atom.CharacterClass { case .verticalWhitespace: return ".verticalWhitespace" case .notVerticalWhitespace: - return ".vertialWhitespace.inverted" + return ".verticalWhitespace.inverted" case .whitespace: return ".whitespace" case .notWhitespace: diff --git a/Tests/RegexTests/RenderDSLTests.swift b/Tests/RegexTests/RenderDSLTests.swift index fbfbee616..aa6b1fa2b 100644 --- a/Tests/RegexTests/RenderDSLTests.swift +++ b/Tests/RegexTests/RenderDSLTests.swift @@ -135,6 +135,32 @@ extension RenderDSLTests { } } """#) + + try testConversion(#"a(?:\w|\W)b(?:\d|\D)c(?:\v|\V)d(?:\h|\H)e"#, #""" + Regex { + "a" + ChoiceOf { + One(.word) + One(.word.inverted) + } + "b" + ChoiceOf { + One(.digit) + One(.digit.inverted) + } + "c" + ChoiceOf { + One(.verticalWhitespace) + One(.verticalWhitespace.inverted) + } + "d" + ChoiceOf { + One(.horizontalWhitespace) + One(.horizontalWhitespace.inverted) + } + "e" + } + """#) } func testOptions() throws { From 77569424217478678b6ae7d2c8be9c7c6e4c90fe Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 9 Feb 2023 11:49:25 -0800 Subject: [PATCH 14/34] Fix output type mismatch with RegexBuilder (#626) Some regex literals (and presumably other `Regex` instances) lose their output type information when used in a RegexBuilder closure due to the way the concatenating builder calls are overloaded. In particular, any output type with labeled tuples or where the sum of tuple components in the accumulated and new output types is greater than 10 will be ignored. Regex internals don't make this distinction, however, so there ends up being a mismatch between what a `Regex.Match` instance tries to produce and the output type of the outermost regex. For example, this code results in a crash, because `regex` is a `Regex` but the match tries to produce a `(Substring, number: Substring)`: let regex = Regex { ZeroOrMore(.whitespace) /:(?\d+):/ ZeroOrMore(.whitespace) } let match = try regex.wholeMatch(in: " :21: ") print(match!.output) To fix this, we add a new `ignoreCapturesInTypedOutput` DSLTree node to mark situations where the output type is discarded. This status is propagated through the capture list into the match's storage, which lets us produce the correct output type. Note that we can't just drop the capture groups when building the compiled program because (1) different parts of the regex might reference the capture group and (2) all capture groups are available if a developer converts the output to `AnyRegexOutput`. let anyOutput = AnyRegexOutput(match) // anyOutput[1] == "21" // anyOutput["number"] == Optional("21") Fixes #625. rdar://104823356 Note: Linux seems to crash on different tests when the two customTest overloads have `internal` visibility or are called. Switching one of the functions to be generic over a RegexComponent works around the issue. --- Package.swift | 6 +- Sources/RegexBuilder/DSL.swift | 62 +++ Sources/RegexBuilder/Variadics.swift | 59 +-- .../VariadicsGenerator.swift | 31 +- .../Regex/Parse/CaptureList.swift | 33 +- Sources/_StringProcessing/ByteCodeGen.swift | 5 +- Sources/_StringProcessing/Capture.swift | 2 +- .../_StringProcessing/ConsumerInterface.swift | 2 +- .../Engine/Structuralize.swift | 3 +- .../_StringProcessing/PrintAsPattern.swift | 3 + .../Regex/AnyRegexOutput.swift | 4 + Sources/_StringProcessing/Regex/DSLTree.swift | 61 ++- .../Utility/RegexFactory.swift | 10 + Tests/RegexBuilderTests/AlgorithmsTests.swift | 2 + .../AnyRegexOutputTests.swift | 1 + Tests/RegexBuilderTests/CustomTests.swift | 161 ++++++-- Tests/RegexBuilderTests/MotivationTests.swift | 7 +- Tests/RegexBuilderTests/RegexDSLTests.swift | 386 ++++++++++++------ Tests/RegexTests/CaptureTests.swift | 6 +- 19 files changed, 605 insertions(+), 239 deletions(-) diff --git a/Package.swift b/Package.swift index b30c402c4..5d45950db 100644 --- a/Package.swift +++ b/Package.swift @@ -8,6 +8,10 @@ let availabilityDefinition = PackageDescription.SwiftSetting.unsafeFlags([ "-define-availability", "-Xfrontend", "SwiftStdlib 5.7:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999", + "-Xfrontend", + "-define-availability", + "-Xfrontend", + "SwiftStdlib 5.8:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999", ]) /// Swift settings for building a private stdlib-like module that is to be used @@ -87,7 +91,7 @@ let package = Package( name: "RegexBuilderTests", dependencies: ["_StringProcessing", "RegexBuilder", "TestSupport"], swiftSettings: [ - .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) + availabilityDefinition ]), .testTarget( name: "DocumentationTests", diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 152aadd0c..680f3bd2f 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -508,3 +508,65 @@ extension Regex.Match { internal func makeFactory() -> _RegexFactory { _RegexFactory() } + +/// These are special `accumulate` methods that wrap one or both components in +/// a node that indicates that that their output types shouldn't be included in +/// the resulting strongly-typed output type. This is required from a +/// `buildPartialBlock` call where a component's output type is either ignored +/// or not included in the resulting type. For example: +/// +/// static func buildPartialBlock( +/// accumulated: R0, next: R1 +/// ) -> Regex<(Substring, C1)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1) +/// +/// In this `buildPartialBlock` overload, `W0` isn't included in the +/// resulting output type, even though it can match any output type, including +/// a tuple. When `W0` matches a tuple type that doesn't match another overload +/// (because of arity or labels) we need this "ignoring" variant so that we +/// don't have a type mismatch when we ultimately cast the type-erased output +/// to the expected type. +@available(SwiftStdlib 5.7, *) +extension _RegexFactory { + /// Concatenates the `left` and `right` component, wrapping `right` to + /// indicate that its output type shouldn't be included in the resulting + /// strongly-typed output type. + @_alwaysEmitIntoClient + internal func accumulate( + _ left: some RegexComponent, + ignoringOutputTypeOf right: some RegexComponent + ) -> Regex { + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + return accumulate(left, ignoreCapturesInTypedOutput(right)) + } + return accumulate(left, right) + } + + /// Concatenates the `left` and `right` component, wrapping `left` to + /// indicate that its output type shouldn't be included in the resulting + /// strongly-typed output type. + @_alwaysEmitIntoClient + internal func accumulate( + ignoringOutputTypeOf left: some RegexComponent, + _ right: some RegexComponent + ) -> Regex { + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + return accumulate(ignoreCapturesInTypedOutput(left), right) + } + return accumulate(left, right) + } + + /// Concatenates the `left` and `right` component, wrapping both sides to + /// indicate that their output types shouldn't be included in the resulting + /// strongly-typed output type. + @_alwaysEmitIntoClient + internal func accumulate( + ignoringOutputTypeOf left: some RegexComponent, + andAlso right: some RegexComponent + ) -> Regex { + if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) { + return accumulate( + ignoreCapturesInTypedOutput(left), ignoreCapturesInTypedOutput(right)) + } + return accumulate(left, right) + } +} diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index 0f19cd6b0..f11727521 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors +// Copyright (c) 2021-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -20,7 +20,7 @@ extension RegexComponentBuilder { accumulated: R0, next: R1 ) -> Regex<(Substring, C1)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } @available(SwiftStdlib 5.7, *) @@ -30,7 +30,7 @@ extension RegexComponentBuilder { accumulated: R0, next: R1 ) -> Regex<(Substring, C1, C2)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } @available(SwiftStdlib 5.7, *) @@ -40,7 +40,7 @@ extension RegexComponentBuilder { accumulated: R0, next: R1 ) -> Regex<(Substring, C1, C2, C3)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } @available(SwiftStdlib 5.7, *) @@ -50,7 +50,7 @@ extension RegexComponentBuilder { accumulated: R0, next: R1 ) -> Regex<(Substring, C1, C2, C3, C4)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } @available(SwiftStdlib 5.7, *) @@ -60,7 +60,7 @@ extension RegexComponentBuilder { accumulated: R0, next: R1 ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } @available(SwiftStdlib 5.7, *) @@ -70,7 +70,7 @@ extension RegexComponentBuilder { accumulated: R0, next: R1 ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } @available(SwiftStdlib 5.7, *) @@ -80,7 +80,7 @@ extension RegexComponentBuilder { accumulated: R0, next: R1 ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } @available(SwiftStdlib 5.7, *) @@ -90,7 +90,7 @@ extension RegexComponentBuilder { accumulated: R0, next: R1 ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } @available(SwiftStdlib 5.7, *) @@ -100,7 +100,7 @@ extension RegexComponentBuilder { accumulated: R0, next: R1 ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } @available(SwiftStdlib 5.7, *) @@ -110,7 +110,7 @@ extension RegexComponentBuilder { accumulated: R0, next: R1 ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } @available(SwiftStdlib 5.7, *) @@ -565,123 +565,112 @@ extension RegexComponentBuilder { } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex where R0.RegexOutput == W0 { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(ignoringOutputTypeOf: accumulated, andAlso: next) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0)> where R0.RegexOutput == (W0, C0) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == (W0, C0, C1) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0, C1, C2) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1, C2, C3) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { - @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient public static func buildPartialBlock( accumulated: R0, next: R1 ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() - return factory.accumulate(accumulated, next) + return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } @@ -6884,7 +6873,3 @@ extension TryCapture { self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } - - - -// END AUTO-GENERATED CONTENT diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index a971dafd7..42673ccfd 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -132,7 +132,7 @@ struct VariadicsGenerator: ParsableCommand { // // This source file is part of the Swift.org open source project // - // Copyright (c) 2021-2022 Apple Inc. and the Swift project authors + // Copyright (c) 2021-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -262,7 +262,20 @@ struct VariadicsGenerator: ParsableCommand { accumulated: R0, next: R1 ) -> \(regexTypeName)<\(matchType)> \(whereClause) { let factory = makeFactory() + + """) + if leftArity == 0 { + output(""" + return factory.accumulate(ignoringOutputTypeOf: accumulated, next) + + """) + } else { + output(""" return factory.accumulate(accumulated, next) + + """) + } + output(""" } } @@ -274,7 +287,6 @@ struct VariadicsGenerator: ParsableCommand { output(""" \(defaultAvailableAttr) extension \(concatBuilderName) { - \(defaultAvailableAttr) @_alwaysEmitIntoClient public static func buildPartialBlock CaptureList { var builder = Self() - builder.captures.append(.init(optionalDepth: 0, .fake)) - builder.addCaptures(of: ast.root, optionalNesting: .init(canNest: false)) + builder.captures.append(.init(optionalDepth: 0, visibleInTypedOutput: true, .fake)) + builder.addCaptures(of: ast.root, optionalNesting: .init(canNest: false), visibleInTypedOutput: true) return builder.captures } } diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index e0a6c7465..15e052901 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -874,7 +874,7 @@ fileprivate extension Compiler.ByteCodeGen { switch node { case .concatenation(let ch): return ch.flatMap(flatten) - case .convertedRegexLiteral(let n, _): + case .convertedRegexLiteral(let n, _), .ignoreCapturesInTypedOutput(let n): return flatten(n) default: return [node] @@ -951,6 +951,9 @@ fileprivate extension Compiler.ByteCodeGen { case let .nonCapturingGroup(kind, child): try emitNoncapturingGroup(kind.ast, child) + case let .ignoreCapturesInTypedOutput(child): + try emitNode(child) + case .conditional: throw Unsupported("Conditionals") diff --git a/Sources/_StringProcessing/Capture.swift b/Sources/_StringProcessing/Capture.swift index b75d01392..696a85361 100644 --- a/Sources/_StringProcessing/Capture.swift +++ b/Sources/_StringProcessing/Capture.swift @@ -61,7 +61,7 @@ extension Sequence where Element == AnyRegexOutput.Element { // and traffic through existentials @available(SwiftStdlib 5.7, *) func existentialOutput(from input: String) -> Any { - let elements = map { + let elements = filter(\.representation.visibleInTypedOutput).map { $0.existentialOutputComponent(from: input) } return elements.count == 1 diff --git a/Sources/_StringProcessing/ConsumerInterface.swift b/Sources/_StringProcessing/ConsumerInterface.swift index 3a2731b0a..705b354fb 100644 --- a/Sources/_StringProcessing/ConsumerInterface.swift +++ b/Sources/_StringProcessing/ConsumerInterface.swift @@ -42,7 +42,7 @@ extension DSLTree.Node { case .orderedChoice, .conditional, .concatenation, .capture, .nonCapturingGroup, .quantification, .trivia, .empty, - .absentFunction: return nil + .ignoreCapturesInTypedOutput, .absentFunction: return nil case .consumer: fatalError("FIXME: Is this where we handle them?") diff --git a/Sources/_StringProcessing/Engine/Structuralize.swift b/Sources/_StringProcessing/Engine/Structuralize.swift index bc3adf701..32d7a6204 100644 --- a/Sources/_StringProcessing/Engine/Structuralize.swift +++ b/Sources/_StringProcessing/Engine/Structuralize.swift @@ -14,7 +14,8 @@ extension CaptureList { optionalDepth: cap.optionalDepth, content: meStored.deconstructed, name: cap.name, - referenceID: list.referencedCaptureOffsets.first { $1 == i }?.key + referenceID: list.referencedCaptureOffsets.first { $1 == i }?.key, + visibleInTypedOutput: cap.visibleInTypedOutput ) result.append(element) diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 234efd3c5..3d2d38842 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -131,6 +131,9 @@ extension PrettyPrinter { printer.printAsPattern(convertedFromAST: child) } + case let .ignoreCapturesInTypedOutput(child): + printAsPattern(convertedFromAST: child, isTopLevel: isTopLevel) + case .conditional: print("/* TODO: conditional */") diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index fd292ed1b..243c1ba01 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -359,6 +359,10 @@ extension AnyRegexOutput { /// The capture reference this element refers to. var referenceID: ReferenceID? = nil + + /// A Boolean value indicating whether this capture should be included in + /// the typed output. + var visibleInTypedOutput: Bool } internal init(input: String, elements: [ElementRepresentation]) { diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index 0a0831706..93e86c607 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -42,6 +42,9 @@ extension DSLTree { /// Matches a noncapturing subpattern. case nonCapturingGroup(_AST.GroupKind, Node) + /// Marks all captures in a subpattern as ignored in strongly-typed output. + case ignoreCapturesInTypedOutput(Node) + // TODO: Consider splitting off grouped conditions, or have // our own kind @@ -340,6 +343,27 @@ typealias _CharacterPredicateInterface = ( */ extension DSLTree.Node { + /// Indicates whether this node has at least one child node (among other + /// associated values). + var hasChildNodes: Bool { + switch self { + case .trivia, .empty, .quotedLiteral, + .consumer, .matcher, .characterPredicate, + .customCharacterClass, .atom: + return false + + case .orderedChoice(let c), .concatenation(let c): + return !c.isEmpty + + case .convertedRegexLiteral, .capture, .nonCapturingGroup, + .quantification, .ignoreCapturesInTypedOutput, .conditional: + return true + + case .absentFunction(let abs): + return !abs.ast.children.isEmpty + } + } + @_spi(RegexBuilder) public var children: [DSLTree.Node] { switch self { @@ -354,6 +378,7 @@ extension DSLTree.Node { case let .capture(_, _, n, _): return [n] case let .nonCapturingGroup(_, n): return [n] case let .quantification(_, _, n): return [n] + case let .ignoreCapturesInTypedOutput(n): return [n] case let .conditional(_, t, f): return [t,f] @@ -403,11 +428,13 @@ extension DSLTree { } extension DSLTree { + /// Indicates whether this DSLTree contains any capture groups. var hasCapture: Bool { root.hasCapture } } extension DSLTree.Node { + /// Indicates whether this DSLTree node contains any capture groups. var hasCapture: Bool { switch self { case .capture: @@ -572,52 +599,55 @@ struct CaptureTransform: Hashable, CustomStringConvertible { extension CaptureList.Builder { mutating func addCaptures( - of node: DSLTree.Node, optionalNesting nesting: OptionalNesting + of node: DSLTree.Node, optionalNesting nesting: OptionalNesting, visibleInTypedOutput: Bool ) { switch node { case let .orderedChoice(children): for child in children { - addCaptures(of: child, optionalNesting: nesting.addingOptional) + addCaptures(of: child, optionalNesting: nesting.addingOptional, visibleInTypedOutput: visibleInTypedOutput) } case let .concatenation(children): for child in children { - addCaptures(of: child, optionalNesting: nesting) + addCaptures(of: child, optionalNesting: nesting, visibleInTypedOutput: visibleInTypedOutput) } case let .capture(name, _, child, transform): captures.append(.init( name: name, type: transform?.resultType ?? child.wholeMatchType, - optionalDepth: nesting.depth, .fake)) - addCaptures(of: child, optionalNesting: nesting) + optionalDepth: nesting.depth, visibleInTypedOutput: visibleInTypedOutput, .fake)) + addCaptures(of: child, optionalNesting: nesting, visibleInTypedOutput: visibleInTypedOutput) case let .nonCapturingGroup(kind, child): assert(!kind.ast.isCapturing) - addCaptures(of: child, optionalNesting: nesting) + addCaptures(of: child, optionalNesting: nesting, visibleInTypedOutput: visibleInTypedOutput) + + case let .ignoreCapturesInTypedOutput(child): + addCaptures(of: child, optionalNesting: nesting, visibleInTypedOutput: false) case let .conditional(cond, trueBranch, falseBranch): switch cond.ast { case .group(let g): - addCaptures(of: .group(g), optionalNesting: nesting) + addCaptures(of: .group(g), optionalNesting: nesting, visibleInTypedOutput: visibleInTypedOutput) default: break } - addCaptures(of: trueBranch, optionalNesting: nesting.addingOptional) - addCaptures(of: falseBranch, optionalNesting: nesting.addingOptional) + addCaptures(of: trueBranch, optionalNesting: nesting.addingOptional, visibleInTypedOutput: visibleInTypedOutput) + addCaptures(of: falseBranch, optionalNesting: nesting.addingOptional, visibleInTypedOutput: visibleInTypedOutput) case let .quantification(amount, _, child): var optNesting = nesting if amount.ast.bounds.atLeast == 0 { optNesting = optNesting.addingOptional } - addCaptures(of: child, optionalNesting: optNesting) + addCaptures(of: child, optionalNesting: optNesting, visibleInTypedOutput: visibleInTypedOutput) case let .absentFunction(abs): switch abs.ast.kind { case .expression(_, _, let child): - addCaptures(of: child, optionalNesting: nesting) + addCaptures(of: child, optionalNesting: nesting, visibleInTypedOutput: visibleInTypedOutput) case .clearer, .repeater, .stopper: break } @@ -625,7 +655,7 @@ extension CaptureList.Builder { case let .convertedRegexLiteral(n, _): // We disable nesting for converted AST trees, as literals do not nest // captures. This includes literals nested in a DSL. - return addCaptures(of: n, optionalNesting: nesting.disablingNesting) + return addCaptures(of: n, optionalNesting: nesting.disablingNesting, visibleInTypedOutput: visibleInTypedOutput) case .matcher: break @@ -639,8 +669,8 @@ extension CaptureList.Builder { static func build(_ dsl: DSLTree) -> CaptureList { var builder = Self() builder.captures.append( - .init(type: dsl.root.wholeMatchType, optionalDepth: 0, .fake)) - builder.addCaptures(of: dsl.root, optionalNesting: .init(canNest: true)) + .init(type: dsl.root.wholeMatchType, optionalDepth: 0, visibleInTypedOutput: true, .fake)) + builder.addCaptures(of: dsl.root, optionalNesting: .init(canNest: true), visibleInTypedOutput: true) return builder.captures } } @@ -650,7 +680,7 @@ extension DSLTree.Node { /// output but forwarding its only child's output. var isOutputForwarding: Bool { switch self { - case .nonCapturingGroup: + case .nonCapturingGroup, .ignoreCapturesInTypedOutput: return true case .orderedChoice, .concatenation, .capture, .conditional, .quantification, .customCharacterClass, .atom, @@ -710,6 +740,7 @@ extension DSLTree { case let .capture(_, _, n, _): return [_Tree(n)] case let .nonCapturingGroup(_, n): return [_Tree(n)] case let .quantification(_, _, n): return [_Tree(n)] + case let .ignoreCapturesInTypedOutput(n): return [_Tree(n)] case let .conditional(_, t, f): return [_Tree(t), _Tree(f)] diff --git a/Sources/_StringProcessing/Utility/RegexFactory.swift b/Sources/_StringProcessing/Utility/RegexFactory.swift index e0df906fa..584772921 100644 --- a/Sources/_StringProcessing/Utility/RegexFactory.swift +++ b/Sources/_StringProcessing/Utility/RegexFactory.swift @@ -20,6 +20,16 @@ public struct _RegexFactory { // Hide is behind an SPI that only RegexBuilder can use. @_spi(RegexBuilder) public init() {} + + @available(SwiftStdlib 5.8, *) + public func ignoreCapturesInTypedOutput( + _ child: some RegexComponent + ) -> Regex { + // Don't wrap `child` again if it's a leaf node. + child.regex.root.hasChildNodes + ? .init(node: .ignoreCapturesInTypedOutput(child.regex.root)) + : .init(node: child.regex.root) + } @available(SwiftStdlib 5.7, *) public func accumulate( diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index dcaddd9d7..7d24e30af 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -13,6 +13,7 @@ import XCTest import _StringProcessing import RegexBuilder +@available(SwiftStdlib 5.7, *) class RegexConsumerTests: XCTestCase { func testMatches() { let regex = Capture(OneOrMore(.digit)) { 2 * Int($0)! } @@ -105,6 +106,7 @@ class RegexConsumerTests: XCTestCase { } } +@available(SwiftStdlib 5.7, *) class AlgorithmsResultBuilderTests: XCTestCase { enum MatchAlgo { case whole diff --git a/Tests/RegexBuilderTests/AnyRegexOutputTests.swift b/Tests/RegexBuilderTests/AnyRegexOutputTests.swift index e6c3214b9..165d1d411 100644 --- a/Tests/RegexBuilderTests/AnyRegexOutputTests.swift +++ b/Tests/RegexBuilderTests/AnyRegexOutputTests.swift @@ -5,6 +5,7 @@ import RegexBuilder private let enablePrinting = false +@available(SwiftStdlib 5.7, *) extension RegexDSLTests { func testContrivedAROExample() { diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index d34b5689f..85186b684 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -14,10 +14,12 @@ import _StringProcessing @testable import RegexBuilder // A nibbler processes a single character from a string +@available(SwiftStdlib 5.7, *) private protocol Nibbler: CustomConsumingRegexComponent { func nibble(_: Character) -> RegexOutput? } +@available(SwiftStdlib 5.7, *) extension Nibbler { // Default implementation, just feed the character in func consuming( @@ -34,6 +36,7 @@ extension Nibbler { // A number nibbler +@available(SwiftStdlib 5.7, *) private struct Numbler: Nibbler { typealias RegexOutput = Int func nibble(_ c: Character) -> Int? { @@ -42,6 +45,7 @@ private struct Numbler: Nibbler { } // An ASCII value nibbler +@available(SwiftStdlib 5.7, *) private struct Asciibbler: Nibbler { typealias RegexOutput = UInt8 func nibble(_ c: Character) -> UInt8? { @@ -49,6 +53,7 @@ private struct Asciibbler: Nibbler { } } +@available(SwiftStdlib 5.7, *) private struct IntParser: CustomConsumingRegexComponent { struct ParseError: Error, Hashable {} typealias RegexOutput = Int @@ -71,6 +76,7 @@ private struct IntParser: CustomConsumingRegexComponent { } } +@available(SwiftStdlib 5.7, *) private struct CurrencyParser: CustomConsumingRegexComponent { enum Currency: String, Hashable { case usd = "USD" @@ -117,9 +123,12 @@ enum MatchCall { case firstMatch } -func customTest( +@available(SwiftStdlib 5.7, *) +fileprivate func customTest( _ regex: Regex, - _ tests: (input: String, call: MatchCall, match: Match?)... + _ tests: (input: String, call: MatchCall, match: Match?)..., + file: StaticString = #file, + line: UInt = #line ) { for (input, call, match) in tests { let result: Match? @@ -129,7 +138,40 @@ func customTest( case .firstMatch: result = input.firstMatch(of: regex)?.output } - XCTAssertEqual(result, match) + XCTAssertEqual(result, match, file: file, line: line) + } +} + +@available(SwiftStdlib 5.7, *) +fileprivate func customTest( + _ regex: some RegexComponent, + _ isEquivalent: (Match, Match) -> Bool, + _ tests: (input: String, call: MatchCall, match: Match?)..., + file: StaticString = #file, + line: UInt = #line +) { + for (input, call, match) in tests { + let result: Match? + switch call { + case .match: + result = input.wholeMatch(of: regex)?.output + case .firstMatch: + result = input.firstMatch(of: regex)?.output + } + switch (result, match) { + case let (result?, match?): + XCTAssert( + isEquivalent(result, match), + "'\(result)' isn't equal to '\(match)'.", + file: file, line: line) + case (nil, nil): + // Success + break + case (nil, _): + XCTFail("No match when expected", file: file, line: line) + case (_, nil): + XCTFail("Unexpected match", file: file, line: line) + } } } @@ -178,6 +220,7 @@ extension Concat: BidirectionalCollection { } } +@available(SwiftStdlib 5.7, *) class CustomRegexComponentTests: XCTestCase { // TODO: Refactor below into more exhaustive, declarative // tests. @@ -211,39 +254,91 @@ class CustomRegexComponentTests: XCTestCase { ("55z", .match, nil), ("55z", .firstMatch, 5)) - // TODO: Convert below tests to better infra. Right now - // it's hard because `Match` is constrained to be - // `Equatable` which tuples cannot be. +// customTest( +// Regex { +// #/(?\D+)/# +// Optionally("~") +// }, +// ("ab123c", .firstMatch, "ab"), +// ("abc", .firstMatch, "abc"), +// ("123", .firstMatch, nil), +// ("a55z", .match, nil), +// ("a55z", .firstMatch, "a")) + + customTest( + Regex<(Substring, Substring, Int)> { + #/(\D+)/# + Capture(Numbler()) + }, + ==, + ("ab123c", .firstMatch, ("ab1", "ab", 1)), + ("abc", .firstMatch, nil), + ("123", .firstMatch, nil), + ("a55z", .match, nil), + ("a55z", .firstMatch, ("a5", "a", 5))) - let regex3 = Regex { - Capture { + customTest( + Regex<(Substring, prefix: Substring)> { + #/(?\D+)/# + }, + ==, + ("ab123c", .firstMatch, ("ab", "ab")), + ("abc", .firstMatch, ("abc", "abc")), + ("123", .firstMatch, nil), + ("a55z", .match, nil), + ("a55z", .firstMatch, ("a", "a"))) + +// customTest( +// Regex<(Substring, Int)> { +// #/(?\D+)/# +// Capture(Numbler()) +// }, +// ==, +// ("ab123c", .firstMatch, ("ab1", 1)), +// ("abc", .firstMatch, nil), +// ("123", .firstMatch, nil), +// ("a55z", .match, nil), +// ("a55z", .firstMatch, ("a5", 5))) + +// customTest( +// Regex<(Substring, Int, Substring)> { +// #/(?\D+)/# +// Regex { +// Capture(Numbler()) +// Capture(OneOrMore(.word)) +// } +// }, +// ==, +// ("ab123c", .firstMatch, ("ab123c", 1, "23c")), +// ("abc", .firstMatch, nil), +// ("123", .firstMatch, nil), +// ("a55z", .match, ("a55z", 5, "5z")), +// ("a55z", .firstMatch, ("a55z", 5, "5z"))) + + customTest( + Regex<(Substring, Substring)> { + Capture { + OneOrMore { + Numbler() + } + } + }, + ==, + ("abc123", .firstMatch, ("123", "123")), + ("abc123", .match, nil), + ("abc", .firstMatch, nil)) + + customTest( + Regex<(Substring, Int)> { OneOrMore { - Numbler() + Capture { Numbler() } } - } - } - - let str = "ab123c" - let res3 = try XCTUnwrap(str.firstMatch(of: regex3)) - - let expectedSubstring = str.dropFirst(2).prefix(3) - XCTAssertEqual(res3.range, expectedSubstring.startIndex.. TransactionKind? in TransactionKind(rawValue: String(s)) } @@ -322,7 +323,7 @@ extension RegexDSLTests { Repeat(.digit, count: 2) Repeat(.digit, count: 2) Repeat(.digit, count: 4) - } transform: { (s: Substring) in + } transform: { (s: Substring) -> Date? in Date(mmddyyyy: String(s)) } @@ -345,7 +346,7 @@ extension RegexDSLTests { OneOrMore(.digit) "." Repeat(.digit, count: 2) - } transform: { (s: Substring) in + } transform: { (s: Substring) -> Double? in Double(s) } } diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 8b7611536..0dd050357 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -14,6 +14,7 @@ import _StringProcessing import RegexBuilder import TestSupport +@available(SwiftStdlib 5.7, *) class RegexDSLTests: XCTestCase { func _testDSLCaptures( _ tests: (input: String, expectedCaptures: MatchType?)..., @@ -52,31 +53,31 @@ class RegexDSLTests: XCTestCase { file: file, line: line) } } - + func testSimpleStrings() throws { let regex = Regex { "a" Capture(Character("b")) // Character - TryCapture("1") { Int($0) } // Int + TryCapture { "1" } transform: { Int($0) } // Int } // Assert the inferred capture type. let _: (Substring, Substring, Int).Type = type(of: regex).RegexOutput.self let maybeMatch = "ab1".wholeMatch(of: regex) let match = try XCTUnwrap(maybeMatch) XCTAssertTrue(match.output == ("ab1", "b", 1)) - + let substring = "ab1"[...] let substringMatch = try XCTUnwrap(substring.wholeMatch(of: regex)) XCTAssertTrue(match.output == substringMatch.output) } - + let allNewlines = "\u{A}\u{B}\u{C}\u{D}\r\n\u{85}\u{2028}\u{2029}" let asciiNewlines = "\u{A}\u{B}\u{C}\u{D}\r\n" - + func testCharacterClasses() throws { // Must have new stdlib for character class ranges. guard ensureNewStdlib() else { return } - + try _testDSLCaptures( ("a c", ("a c", " ", "c")), matchType: (Substring, Substring, Substring).self, ==) @@ -94,7 +95,7 @@ class RegexDSLTests: XCTestCase { OneOrMore { CharacterClass("a"..."z", .digit) } - + // Second group OneOrMore { ChoiceOf { @@ -103,7 +104,7 @@ class RegexDSLTests: XCTestCase { } } } - + try _testDSLCaptures( ("abc1def2", ("abc1def2", "abc1")), matchType: (Substring, Substring).self, ==) @@ -112,12 +113,12 @@ class RegexDSLTests: XCTestCase { OneOrMore(.digit.inverted) ("a"..."z").inverted } - + OneOrMore { CharacterClass.whitespace.inverted } } - + // `.newlineSequence` and `.verticalWhitespace` match the same set of // newlines in grapheme semantic mode, and scalar mode when applied with // OneOrMore. @@ -146,7 +147,7 @@ class RegexDSLTests: XCTestCase { } }.matchingSemantics(mode) } - + // Try with ASCII-only whitespace. try _testDSLCaptures( ("\n", ("\n", "\n")), @@ -173,7 +174,7 @@ class RegexDSLTests: XCTestCase { } } } - + // `.newlineSequence` in scalar mode may match a single `\r\n`. // `.verticalWhitespace` may not. for asciiOnly in [true, false] { @@ -224,7 +225,7 @@ class RegexDSLTests: XCTestCase { }.matchingSemantics(.unicodeScalar).asciiOnlyWhitespace(asciiOnly) } } - + // Make sure horizontal whitespace does not match newlines or other // vertical whitespace. try _testDSLCaptures( @@ -237,7 +238,7 @@ class RegexDSLTests: XCTestCase { { OneOrMore(.horizontalWhitespace) } - + // Horizontal whitespace in ASCII mode. try _testDSLCaptures( (" \u{9} \t ", " \u{9} \t "), @@ -249,11 +250,11 @@ class RegexDSLTests: XCTestCase { }.asciiOnlyWhitespace() } } - + func testCharacterClassOperations() throws { // Must have new stdlib for character class ranges. guard ensureNewStdlib() else { return } - + try _testDSLCaptures( ("bcdefn1a", "bcdefn1a"), ("nbcdef1a", nil), // fails symmetric difference lookahead @@ -265,15 +266,15 @@ class RegexDSLTests: XCTestCase { let disallowedChars = CharacterClass.hexDigit .symmetricDifference("a"..."z") NegativeLookahead(disallowedChars) // No: 0-9 + g-z - + OneOrMore(("b"..."g").union("d"..."n")) // b-n CharacterClass.digit.subtracting("3"..."9") // 1, 2, non-ascii digits - + CharacterClass.hexDigit.intersection("a"..."z") // a-f } } - + func testAny() throws { // .any matches newlines regardless of matching options. for dotMatchesNewline in [true, false] { @@ -286,7 +287,7 @@ class RegexDSLTests: XCTestCase { }.dotMatchesNewlines(dotMatchesNewline) } } - + // `.anyGraphemeCluster` is the same as `.any` in grapheme mode. for mode in [RegexSemanticLevel.graphemeCluster, .unicodeScalar] { try _testDSLCaptures( @@ -301,7 +302,7 @@ class RegexDSLTests: XCTestCase { One(.anyGraphemeCluster) }.matchingSemantics(mode) } - + // Like `.any` it also always matches newlines. for dotMatchesNewline in [true, false] { try _testDSLCaptures( @@ -315,7 +316,7 @@ class RegexDSLTests: XCTestCase { } } } - + func testAnyNonNewline() throws { // `.anyNonNewline` is `.` without single-line mode. for mode in [RegexSemanticLevel.graphemeCluster, .unicodeScalar] { @@ -332,7 +333,7 @@ class RegexDSLTests: XCTestCase { OneOrMore(.anyNonNewline) }.matchingSemantics(mode).dotMatchesNewlines(dotMatchesNewline) } - + try _testDSLCaptures( ("abcdef", nil), ("abcdef\n", nil), @@ -345,7 +346,7 @@ class RegexDSLTests: XCTestCase { OneOrMore(.anyNonNewline.inverted) }.matchingSemantics(mode).dotMatchesNewlines(dotMatchesNewline) } - + try _testDSLCaptures( ("abc", "abc"), ("abcd", nil), @@ -360,7 +361,7 @@ class RegexDSLTests: XCTestCase { } } } - + try _testDSLCaptures( ("\r\n", "\r\n"), matchType: Substring.self, ==) { CharacterClass.anyNonNewline.inverted @@ -372,12 +373,12 @@ class RegexDSLTests: XCTestCase { }.matchingSemantics(.unicodeScalar) } } - + func testMatchResultDotZeroWithoutCapture() throws { let match = try XCTUnwrap("aaa".wholeMatch { OneOrMore { "a" } }) XCTAssertEqual(match.0, "aaa") } - + func testAlternation() throws { do { let regex = ChoiceOf { @@ -446,7 +447,7 @@ class RegexDSLTests: XCTestCase { XCTAssertNil("aab".wholeMatch(of: regex)?.output) } } - + func testCombinators() throws { try _testDSLCaptures( ("aaaabccccdddkj", ("aaaabccccdddkj", "b", "cccc", "d", "k", nil, "j")), @@ -497,7 +498,7 @@ class RegexDSLTests: XCTestCase { .ignoresCase(true) .ignoresCase(false) } - + // An option on an outer component doesn't override an option set on an // inner component. try _testDSLCaptures( @@ -518,7 +519,7 @@ class RegexDSLTests: XCTestCase { } .ignoresCase(false) } - + // FIXME: Re-enable this test try _testDSLCaptures( ("can't stop won't stop", ("can't stop won't stop", "can't", "won't")), @@ -538,7 +539,7 @@ class RegexDSLTests: XCTestCase { OneOrMore(.any, .reluctant) "stop" } - + // FIXME: Re-enable this test try _testDSLCaptures( ("can't stop won't stop", ("can't stop won't stop", "can", "won")), @@ -599,7 +600,7 @@ class RegexDSLTests: XCTestCase { func testQuantificationBehavior() throws { // Must have new stdlib for character class ranges. guard ensureNewStdlib() else { return } - + // Eager by default try _testDSLCaptures( ("abc1def2", ("abc1def2", "2")), @@ -609,7 +610,7 @@ class RegexDSLTests: XCTestCase { Capture(.digit) ZeroOrMore(.any) } - + // Explicitly reluctant try _testDSLCaptures( ("abc1def2", ("abc1def2", "1")), @@ -700,7 +701,7 @@ class RegexDSLTests: XCTestCase { OneOrMore("a") }.repetitionBehavior(.possessive) } - + try _testDSLCaptures( ("abc1def2", "abc1def2"), matchType: Substring.self, ==) @@ -712,7 +713,7 @@ class RegexDSLTests: XCTestCase { CharacterClass.digit } } - + try _testDSLCaptures( ("abcdef2", ("abcdef2", "f")), ("2", ("2", nil)), @@ -726,7 +727,7 @@ class RegexDSLTests: XCTestCase { CharacterClass.digit } } - + try _testDSLCaptures( ("aaabbbcccdddeeefff", "aaabbbcccdddeeefff"), ("aaabbbcccccdddeeefff", "aaabbbcccccdddeeefff"), @@ -748,7 +749,7 @@ class RegexDSLTests: XCTestCase { Repeat(2...) { "e" } Repeat(0...) { "f" } } - + try _testDSLCaptures( ("", nil), ("a", nil), @@ -758,7 +759,7 @@ class RegexDSLTests: XCTestCase { { Repeat(2...) { "a" } } - + try _testDSLCaptures( ("", ""), ("a", "a"), @@ -768,7 +769,7 @@ class RegexDSLTests: XCTestCase { { Repeat(...2) { "a" } } - + try _testDSLCaptures( ("", ""), ("a", "a"), @@ -778,7 +779,7 @@ class RegexDSLTests: XCTestCase { { Repeat(..<2) { "a" } } - + try _testDSLCaptures( ("", ""), ("a", nil), @@ -787,7 +788,7 @@ class RegexDSLTests: XCTestCase { { Repeat(...0) { "a" } } - + try _testDSLCaptures( ("", ""), ("a", nil), @@ -796,7 +797,7 @@ class RegexDSLTests: XCTestCase { { Repeat(0 ... 0) { "a" } } - + try _testDSLCaptures( ("", ""), ("a", nil), @@ -805,7 +806,7 @@ class RegexDSLTests: XCTestCase { { Repeat(count: 0) { "a" } } - + try _testDSLCaptures( ("", ""), ("a", "a"), @@ -814,7 +815,7 @@ class RegexDSLTests: XCTestCase { { Repeat(0 ... 1) { "a" } } - + try _testDSLCaptures( ("", nil), ("a", "a"), @@ -824,7 +825,7 @@ class RegexDSLTests: XCTestCase { { Repeat(1 ... 2) { "a" } } - + try _testDSLCaptures( ("", ""), ("a", nil), @@ -833,7 +834,7 @@ class RegexDSLTests: XCTestCase { { Repeat(0 ..< 1) { "a" } } - + try _testDSLCaptures( ("", ""), ("a", "a"), @@ -842,7 +843,7 @@ class RegexDSLTests: XCTestCase { { Repeat(0 ..< 2) { "a" } } - + try _testDSLCaptures( ("", nil), ("a", "a"), @@ -852,7 +853,7 @@ class RegexDSLTests: XCTestCase { { Repeat(1 ..< 3) { "a" } } - + let octoDecimalRegex: Regex<(Substring, Int?)> = Regex { let charClass = CharacterClass(.digit, "a"..."h")//.ignoringCase() Capture { @@ -907,7 +908,7 @@ class RegexDSLTests: XCTestCase { UnicodeScalar("e") Anchor.textSegmentBoundary } - + try _testDSLCaptures( ("aaaaa1", "aaaaa1"), ("aaaaa2", nil), @@ -934,7 +935,7 @@ class RegexDSLTests: XCTestCase { Anchor.endOfSubject }.anchorsMatchLineEndings() } - + try _testDSLCaptures( ("\naaa", "\naaa"), ("aaa\n", "aaa\n"), @@ -949,7 +950,7 @@ class RegexDSLTests: XCTestCase { Optionally { "\n" } } } - + // startOfLine/endOfLine apply regardless of mode. for matchLineEndings in [true, false] { for mode in [RegexSemanticLevel.graphemeCluster, .unicodeScalar] { @@ -958,41 +959,41 @@ class RegexDSLTests: XCTestCase { Repeat("a", count: 3) Anchor.endOfLine }.anchorsMatchLineEndings(matchLineEndings).matchingSemantics(mode) - + XCTAssertNotNil(try r.firstMatch(in: "\naaa")) XCTAssertNotNil(try r.firstMatch(in: "aaa\n")) XCTAssertNotNil(try r.firstMatch(in: "\naaa\n")) XCTAssertNotNil(try r.firstMatch(in: "\naaa\r\n")) XCTAssertNotNil(try r.firstMatch(in: "\r\naaa\n")) XCTAssertNotNil(try r.firstMatch(in: "\r\naaa\r\n")) - + XCTAssertNil(try r.firstMatch(in: "\nbaaa\n")) XCTAssertNil(try r.firstMatch(in: "\naaab\n")) } } } - + func testNestedGroups() throws { return; - + // TODO: clarify what the nesting story is - + /* - try _testDSLCaptures( - ("aaaabccccddd", ("aaaabccccddd", [("b", "cccc", ["d", "d", "d"])])), - matchType: (Substring, [(Substring, Substring, [Substring])]).self, ==) - { - "a".+ - OneOrMore { - Capture(OneOrMore("b")) - Capture(ZeroOrMore("c")) - Capture("d").* - "e".? - } - } + try _testDSLCaptures( + ("aaaabccccddd", ("aaaabccccddd", [("b", "cccc", ["d", "d", "d"])])), + matchType: (Substring, [(Substring, Substring, [Substring])]).self, ==) + { + "a".+ + OneOrMore { + Capture(OneOrMore("b")) + Capture(ZeroOrMore("c")) + Capture("d").* + "e".? + } + } */ } - + func testCaptureTransform() throws { try _testDSLCaptures( ("aaaa1", ("aaaa1", "aaa")), @@ -1015,7 +1016,7 @@ class RegexDSLTests: XCTestCase { One(.digit) } } - + func testCapturelessQuantification() throws { // This test is to make sure that a captureless quantification, when used // straight out of the quantifier (without being wrapped in a builder), is @@ -1028,7 +1029,7 @@ class RegexDSLTests: XCTestCase { let match = try XCTUnwrap(input.wholeMatch(of: regex)?.output) XCTAssertTrue(match == input) } - + func testQuantificationWithTransformedCapture() throws { // This test is to make sure transformed capture type information is // correctly propagated from the DSL into the bytecode and that the engine @@ -1037,7 +1038,7 @@ class RegexDSLTests: XCTestCase { enum Word: Int32 { case apple case orange - + init?(_ string: Substring) { switch string { case "apple": self = .apple @@ -1062,7 +1063,7 @@ class RegexDSLTests: XCTestCase { } } } - + func testNestedCaptureTypes() throws { let regex1 = Regex { OneOrMore("a") @@ -1072,8 +1073,8 @@ class RegexDSLTests: XCTestCase { } } let _: (Substring, Substring, Substring).Type - = type(of: regex1).RegexOutput.self - + = type(of: regex1).RegexOutput.self + let regex2 = Regex { OneOrMore("a") Capture { @@ -1084,8 +1085,8 @@ class RegexDSLTests: XCTestCase { } } let _: (Substring, Substring, Int?).Type - = type(of: regex2).RegexOutput.self - + = type(of: regex2).RegexOutput.self + let regex3 = Regex { OneOrMore("a") Capture { @@ -1097,8 +1098,8 @@ class RegexDSLTests: XCTestCase { } } let _: (Substring, Substring, Int, Double?).Type - = type(of: regex3).RegexOutput.self - + = type(of: regex3).RegexOutput.self + let regex4 = Regex { OneOrMore("a") Capture { @@ -1112,50 +1113,50 @@ class RegexDSLTests: XCTestCase { } let _: ( Substring, Substring, Substring, Substring, Substring?).Type - = type(of: regex4).RegexOutput.self + = type(of: regex4).RegexOutput.self } - + func testUnicodeScalarPostProcessing() throws { let spaces = Regex { ZeroOrMore { One(.whitespace) } } - + let unicodeScalar = Regex { OneOrMore { One(.hexDigit) } spaces } - + let unicodeData = Regex { unicodeScalar Optionally { ".." unicodeScalar } - + ";" spaces - + Capture { OneOrMore(.word) } - + ZeroOrMore(.any) } - + // Assert the inferred capture type. let _: (Substring, Substring).Type = type(of: unicodeData).RegexOutput.self - + let unicodeLine = - "1BCA0..1BCA3 ; Control # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP" + "1BCA0..1BCA3 ; Control # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP" let match = try XCTUnwrap(unicodeLine.wholeMatch(of: unicodeData)) XCTAssertEqual(match.0, Substring(unicodeLine)) XCTAssertEqual(match.1, "Control") } - + func testGraphemeBreakData() throws { let line = """ A6F0..A6F1 ; Extend # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS @@ -1191,7 +1192,7 @@ class RegexDSLTests: XCTestCase { XCTAssertEqual(upper, Unicode.Scalar(0xA6F1)) XCTAssertEqual(propertyString, "Extend") } - + let regexWithTryCapture = Regex { TryCapture { OneOrMore(.hexDigit) @@ -1226,10 +1227,10 @@ class RegexDSLTests: XCTestCase { XCTAssertEqual(upper, Unicode.Scalar(0xA6F1)) XCTAssertEqual(propertyString, "Extend") } - + do { let regexLiteral = try Regex( - #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, + #"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#, as: (Substring, Substring, Substring?, Substring).self) let maybeMatchResult = line.wholeMatch(of: regexLiteral) let matchResult = try XCTUnwrap(maybeMatchResult) @@ -1240,7 +1241,7 @@ class RegexDSLTests: XCTestCase { XCTAssertEqual(propertyString, "Extend") } } - + func testBackreference() throws { try _testDSLCaptures( ("abc#41#42abcabcabc", ("abc#41#42abcabcabc", "abc", 42, "abc", nil)), @@ -1266,7 +1267,7 @@ class RegexDSLTests: XCTestCase { Capture(a) } } - + // Match result referencing a `Reference`. do { let a = Reference(Substring.self) @@ -1294,7 +1295,7 @@ class RegexDSLTests: XCTestCase { XCTAssertEqual(result[a], "abc") XCTAssertEqual(result[b], 42) } - + do { let key = Reference(Substring.self) let value = Reference(Int.self) @@ -1312,15 +1313,15 @@ class RegexDSLTests: XCTestCase { } transform: { Int($0)! } } } - + let result1 = try XCTUnwrap("age:123".wholeMatch(of: regex)) XCTAssertEqual(result1[key], "age") XCTAssertEqual(result1[value], 123) - + let result2 = try XCTUnwrap(":567".wholeMatch(of: regex)) XCTAssertEqual(result2[key], "") XCTAssertEqual(result2[value], 567) - + let result3 = try XCTUnwrap("status:".wholeMatch(of: regex)) XCTAssertEqual(result3[key], "status") // Traps: @@ -1351,7 +1352,7 @@ class RegexDSLTests: XCTestCase { } } } - + // Post-hoc captured reference w/ attempted match before capture // #"(?:\w\1|(\w):)+"# // @@ -1400,7 +1401,7 @@ class RegexDSLTests: XCTestCase { } } } - + func testScalarMatching() throws { // RegexBuilder provides a RegexComponent conformance for UnicodeScalar. In // grapheme cluster mode, it should only match entire graphemes. It may @@ -1409,7 +1410,7 @@ class RegexDSLTests: XCTestCase { XCTAssertNil("a\u{301}".firstMatch(of: "a" as UnicodeScalar)) XCTAssertNotNil("a\u{301}".firstMatch( of: ("a" as UnicodeScalar).regex.matchingSemantics(.unicodeScalar))) - + let r1 = Regex { "a" as UnicodeScalar } @@ -1417,7 +1418,7 @@ class RegexDSLTests: XCTestCase { XCTAssertNotNil( try r1.matchingSemantics(.unicodeScalar).firstMatch(in: "a\u{301}") ) - + let r2 = Regex { CharacterClass.anyOf(["a" as UnicodeScalar, "👍"]) } @@ -1425,7 +1426,7 @@ class RegexDSLTests: XCTestCase { XCTAssertNotNil( try r2.matchingSemantics(.unicodeScalar).firstMatch(in: "a\u{301}") ) - + let r3 = Regex { "👨" as UnicodeScalar "\u{200D}" as UnicodeScalar @@ -1439,7 +1440,7 @@ class RegexDSLTests: XCTestCase { XCTAssertNotNil(try r3.wholeMatch(in: "👨‍👨‍👧‍👦")) XCTAssertNotNil(try r3.matchingSemantics(.unicodeScalar).firstMatch(in: "👨‍👨‍👧‍👦")) XCTAssertNotNil(try r3.matchingSemantics(.unicodeScalar).wholeMatch(in: "👨‍👨‍👧‍👦")) - + let r4 = Regex { "é" as UnicodeScalar } XCTAssertNotNil( try r4.firstMatch(in: "e\u{301}") @@ -1447,28 +1448,28 @@ class RegexDSLTests: XCTestCase { XCTAssertNotNil( try r4.firstMatch(in: "é") ) - + let r5 = Regex { "e" "\u{301}" as UnicodeScalar } XCTAssertNotNil(try r5.firstMatch(in: "e\u{301}")) XCTAssertNotNil(try r5.firstMatch(in: "é")) - + let r6 = Regex { "abcde" "\u{301}" } XCTAssertNotNil(try r6.firstMatch(in: "abcde\u{301}")) XCTAssertNotNil(try r6.firstMatch(in: "abcdé")) - + let r7 = Regex { "e" as Character "\u{301}" as Character } XCTAssertNotNil(try r7.firstMatch(in: "e\u{301}")) XCTAssertNotNil(try r7.firstMatch(in: "é")) - + // You can't match a partial grapheme in grapheme semantic mode. let r8 = Regex { "👨" as UnicodeScalar @@ -1481,7 +1482,7 @@ class RegexDSLTests: XCTestCase { XCTAssertNil(try r8.wholeMatch(in: "👨‍👨‍👧‍👦")) XCTAssertNotNil(try r8.matchingSemantics(.unicodeScalar).firstMatch(in: "👨‍👨‍👧‍👦")) XCTAssertNil(try r8.matchingSemantics(.unicodeScalar).wholeMatch(in: "👨‍👨‍👧‍👦")) - + // Scalar coalescing occurs across nested concatenations and literals. let r9 = Regex { Regex { @@ -1503,7 +1504,7 @@ class RegexDSLTests: XCTestCase { XCTAssertNotNil(try r9.wholeMatch(in: "👨‍👨‍👧‍👦")) XCTAssertNotNil(try r9.matchingSemantics(.unicodeScalar).firstMatch(in: "👨‍👨‍👧‍👦")) XCTAssertNotNil(try r9.matchingSemantics(.unicodeScalar).wholeMatch(in: "👨‍👨‍👧‍👦")) - + let r10 = Regex { "👨" as UnicodeScalar try! Regex(#"\u{200D 1F468 200D 1F467}"#) @@ -1515,7 +1516,7 @@ class RegexDSLTests: XCTestCase { XCTAssertNotNil(try r10.matchingSemantics(.unicodeScalar).firstMatch(in: "👨‍👨‍👧‍👦")) XCTAssertNotNil(try r10.matchingSemantics(.unicodeScalar).wholeMatch(in: "👨‍👨‍👧‍👦")) } - + struct SemanticVersion: Equatable { var major: Int var minor: Int @@ -1542,11 +1543,11 @@ class RegexDSLTests: XCTestCase { Capture(OneOrMore(.word)) } } - + guard let match = input[index..) throws -> (upperBound: String.Index, output: Void)? { print("Matching '\(label)'", to: &Self.traceOutput) print(input, to: &Self.traceOutput) @@ -1611,7 +1612,7 @@ class RegexDSLTests: XCTestCase { """) } - + func testRegexComponentBuilderResultType() { // Test that the user can declare a closure or computed property marked with // `@RegexComponentBuilder` with `Regex` as the result type. @@ -1654,7 +1655,7 @@ class RegexDSLTests: XCTestCase { XCTAssertEqual(try replace("{bar}"), "foo") } - + func testOptionalNesting() throws { try _testDSLCaptures( ("a", ("a", nil)), @@ -1665,7 +1666,7 @@ class RegexDSLTests: XCTestCase { { try! Regex("(?:a|(b)*)?", as: (Substring, Substring?).self) } - + try _testDSLCaptures( ("a", ("a", nil)), ("", ("", nil)), @@ -1677,7 +1678,7 @@ class RegexDSLTests: XCTestCase { try! Regex("a|(b)*", as: (Substring, Substring?).self) } } - + try _testDSLCaptures( ("a", ("a", nil)), ("", ("", nil)), @@ -1692,7 +1693,7 @@ class RegexDSLTests: XCTestCase { } } } - + try _testDSLCaptures( ("a", ("a", nil)), ("", ("", nil)), @@ -1705,7 +1706,7 @@ class RegexDSLTests: XCTestCase { try! Regex("(b)*", as: (Substring, Substring?).self) } } - + try _testDSLCaptures( ("a", ("a", nil)), ("", ("", nil)), @@ -1720,7 +1721,7 @@ class RegexDSLTests: XCTestCase { } } } - + try _testDSLCaptures( ("a", ("a", nil)), ("", ("", nil)), @@ -1737,7 +1738,7 @@ class RegexDSLTests: XCTestCase { } } } - + let r = Regex { Optionally { Optionally { @@ -1757,6 +1758,139 @@ class RegexDSLTests: XCTestCase { } } +fileprivate let oneNumericField = "abc:123:def" +fileprivate let twoNumericFields = "abc:123:def:456:ghi" + +@available(SwiftStdlib 5.7, *) +fileprivate let regexWithCapture = #/:(\d+):/# +@available(SwiftStdlib 5.7, *) +fileprivate let regexWithLabeledCapture = #/:(?\d+):/# +@available(SwiftStdlib 5.7, *) +fileprivate let regexWithNonCapture = #/:(?:\d+):/# + +@available(SwiftStdlib 5.7, *) +extension RegexDSLTests { + func testLabeledCaptures_regularCapture() throws { + // The output type of a regex with unlabeled captures is concatenated. + let dslWithCapture = Regex { + OneOrMore(.word) + regexWithCapture + OneOrMore(.word) + } + XCTAssert(type(of: dslWithCapture).self == Regex<(Substring, Substring)>.self) + + let output = try XCTUnwrap(oneNumericField.wholeMatch(of: dslWithCapture)?.output) + XCTAssertEqual(output.0, oneNumericField[...]) + XCTAssertEqual(output.1, "123") + } + + func testLabeledCaptures_labeledCapture() throws { + guard #available(macOS 13, *) else { + XCTSkip("Fix only exists on macOS 13") + return + } + // The output type of a regex with a labeled capture is dropped. + let dslWithLabeledCapture = Regex { + OneOrMore(.word) + regexWithLabeledCapture + OneOrMore(.word) + } + XCTAssert(type(of: dslWithLabeledCapture).self == Regex.self) + + let match = try XCTUnwrap(oneNumericField.wholeMatch(of: dslWithLabeledCapture)) + XCTAssertEqual(match.output, oneNumericField[...]) + + // We can recover the ignored captures by converting to `AnyRegexOutput`. + let anyOutput = AnyRegexOutput(match) + XCTAssertEqual(anyOutput.count, 2) + XCTAssertEqual(anyOutput[0].substring, oneNumericField[...]) + XCTAssertEqual(anyOutput[1].substring, "123") + XCTAssertEqual(anyOutput["number"]?.substring, "123") + } + + func testLabeledCaptures_coalescingWithCapture() throws { + let coalescingWithCapture = Regex { + "e" as Character + #/\u{301}(\d*)/# + } + XCTAssertNotNil(try coalescingWithCapture.firstMatch(in: "e\u{301}")) + XCTAssertNotNil(try coalescingWithCapture.firstMatch(in: "é")) + + let coalescingWithLabeledCapture = Regex { + "e" as Character + #/\u{301}(?\d*)/# + } + XCTAssertNotNil(try coalescingWithLabeledCapture.firstMatch(in: "e\u{301}")) + XCTAssertNotNil(try coalescingWithLabeledCapture.firstMatch(in: "é")) + } + + func testLabeledCaptures_bothCapture() throws { + guard #available(macOS 13, *) else { + XCTSkip("Fix only exists on macOS 13") + return + } + // Only the output type of a regex with a labeled capture is dropped, + // outputs of other regexes in the same DSL are concatenated. + let dslWithBothCaptures = Regex { + OneOrMore(.word) + regexWithCapture + OneOrMore(.word) + regexWithLabeledCapture + OneOrMore(.word) + } + XCTAssert(type(of: dslWithBothCaptures).self == Regex<(Substring, Substring)>.self) + + let match = try XCTUnwrap(twoNumericFields.wholeMatch(of: dslWithBothCaptures)) + XCTAssertEqual(match.output.0, twoNumericFields[...]) + XCTAssertEqual(match.output.1, "123") + + let anyOutput = AnyRegexOutput(match) + XCTAssertEqual(anyOutput.count, 3) + XCTAssertEqual(anyOutput[0].substring, twoNumericFields[...]) + XCTAssertEqual(anyOutput[1].substring, "123") + XCTAssertEqual(anyOutput[2].substring, "456") + } + + func testLabeledCaptures_tooManyCapture() throws { + guard #available(macOS 13, *) else { + XCTSkip("Fix only exists on macOS 13") + return + } + // The output type of a regex with too many captures is dropped. + // "Too many" means the left and right output types would add up to >= 10. + let alpha = "AAA:abcdefghijklm:123:456:" + let regexWithTooManyCaptures = #/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)/# + let dslWithTooManyCaptures = Regex { + Capture(OneOrMore(.word)) + ":" + regexWithTooManyCaptures + ":" + TryCapture(OneOrMore(.word)) { Int($0) } + #/:(\d+):/# + } + XCTAssert(type(of: dslWithTooManyCaptures).self + == Regex<(Substring, Substring, Int, Substring)>.self) + + let match = try XCTUnwrap(alpha.wholeMatch(of: dslWithTooManyCaptures)) + XCTAssertEqual(match.output.0, alpha[...]) + XCTAssertEqual(match.output.1, "AAA") + XCTAssertEqual(match.output.2, 123) + XCTAssertEqual(match.output.3, "456") + + // All captures groups are available through `AnyRegexOutput`. + let anyOutput = AnyRegexOutput(match) + XCTAssertEqual(anyOutput.count, 17) + XCTAssertEqual(anyOutput[0].substring, alpha[...]) + XCTAssertEqual(anyOutput[1].substring, "AAA") + for (offset, letter) in "abcdefghijklm".enumerated() { + XCTAssertEqual(anyOutput[offset + 2].substring, String(letter)[...]) + } + XCTAssertEqual(anyOutput[15].substring, "123") + XCTAssertEqual(anyOutput[15].value as? Int, 123) + XCTAssertEqual(anyOutput[16].substring, "456") + } +} + extension Unicode.Scalar { // Convert a hexadecimal string to a scalar init?(hex: S) { diff --git a/Tests/RegexTests/CaptureTests.swift b/Tests/RegexTests/CaptureTests.swift index 26093bc64..85aecd210 100644 --- a/Tests/RegexTests/CaptureTests.swift +++ b/Tests/RegexTests/CaptureTests.swift @@ -16,15 +16,15 @@ import XCTest extension CaptureList.Capture { static var cap: Self { - return Self(optionalDepth: 0, .fake) + return Self(optionalDepth: 0, visibleInTypedOutput: true, .fake) } static var opt: Self { - return Self(optionalDepth: 1, .fake) + return Self(optionalDepth: 1, visibleInTypedOutput: true, .fake) } static func named(_ name: String, opt: Int = 0) -> Self { - return Self(name: name, optionalDepth: opt, .fake) + return Self(name: name, optionalDepth: opt, visibleInTypedOutput: true, .fake) } } extension CaptureList { From 070e0ec3e02aef8e2a3ce3b29a8330ef4572beda Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 14 Feb 2023 23:23:04 -0600 Subject: [PATCH 15/34] Revert "Merge pull request #628 from apple/result_builder_changes_workaround" This reverts commit 7e059b7bd4e647bc884a71731fcfdc4fffda0700, reversing changes made to 3ca8b134e4c93e8c6d3f7b060b0aefcf06b92039. --- .../_StringProcessing/MatchingOptions.swift | 12 +++--------- Tests/RegexBuilderTests/CustomTests.swift | 18 +++++++++--------- Tests/RegexBuilderTests/MotivationTests.swift | 12 ++++++------ Tests/RegexBuilderTests/RegexDSLTests.swift | 10 +++++----- 4 files changed, 23 insertions(+), 29 deletions(-) diff --git a/Sources/_StringProcessing/MatchingOptions.swift b/Sources/_StringProcessing/MatchingOptions.swift index 60cc7d0de..d511c9f7c 100644 --- a/Sources/_StringProcessing/MatchingOptions.swift +++ b/Sources/_StringProcessing/MatchingOptions.swift @@ -14,9 +14,7 @@ /// A type that represents the current state of regex matching options, with /// stack-based scoping. struct MatchingOptions { - // FIXME: Workaround for rdar://104923020 - // fileprivate - var stack: [Representation] + fileprivate var stack: [Representation] fileprivate func _invariantCheck() { assert(!stack.isEmpty, "Unbalanced call to endScope") @@ -127,9 +125,7 @@ extension MatchingOptions { // MARK: - Implementation extension MatchingOptions { /// An option that changes the behavior of a regular expression. - // FIXME: Workaround for rdar://104923020 - // fileprivate - enum Option: Int { + fileprivate enum Option: Int { // PCRE options case caseInsensitive case allowDuplicateGroupNames @@ -216,9 +212,7 @@ extension MatchingOptions { extension MatchingOptions { /// A set of matching options. - // FIXME: Workaround for rdar://104923020 - // fileprivate - struct Representation: OptionSet, RawRepresentable { + fileprivate struct Representation: OptionSet, RawRepresentable { var rawValue: UInt32 /// Returns `true` if the option denoted by `kind` is a member of this set. diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index 85186b684..26746d613 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -226,7 +226,7 @@ class CustomRegexComponentTests: XCTestCase { // tests. func testCustomRegexComponents() throws { customTest( - Regex { + Regex { Numbler() Asciibbler() }, @@ -237,7 +237,7 @@ class CustomRegexComponentTests: XCTestCase { ("t4", .match, nil)) customTest( - Regex { + Regex { OneOrMore { Numbler() } }, ("ab123c", .firstMatch, "123"), @@ -520,7 +520,7 @@ class CustomRegexComponentTests: XCTestCase { ) customTest( - Regex { + Regex { CurrencyParser() }, ("USD", .usd, nil), @@ -532,7 +532,7 @@ class CustomRegexComponentTests: XCTestCase { // No capture, two errors customTest( - Regex { + Regex { IntParser() " " IntParser() @@ -544,7 +544,7 @@ class CustomRegexComponentTests: XCTestCase { ) customTest( - Regex { + Regex { CurrencyParser() IntParser() }, @@ -557,7 +557,7 @@ class CustomRegexComponentTests: XCTestCase { // One capture, two errors: One error is thrown from inside a capture, // while the other one is thrown from outside customTest( - Regex<(Substring, CurrencyParser.Currency)> { + Regex { Capture { CurrencyParser() } IntParser() }, @@ -568,7 +568,7 @@ class CustomRegexComponentTests: XCTestCase { ) customTest( - Regex<(Substring, Int)> { + Regex { CurrencyParser() Capture { IntParser() } }, @@ -580,7 +580,7 @@ class CustomRegexComponentTests: XCTestCase { // One capture, two errors: Both errors are thrown from inside the capture customTest( - Regex<(Substring, Substring)> { + Regex { Capture { CurrencyParser() IntParser() @@ -594,7 +594,7 @@ class CustomRegexComponentTests: XCTestCase { // Two captures, two errors: Different erros are thrown from inside captures customTest( - Regex<(Substring, CurrencyParser.Currency, Int)> { + Regex { Capture(CurrencyParser()) Capture(IntParser()) }, diff --git a/Tests/RegexBuilderTests/MotivationTests.swift b/Tests/RegexBuilderTests/MotivationTests.swift index 06511d5b8..8e4391754 100644 --- a/Tests/RegexBuilderTests/MotivationTests.swift +++ b/Tests/RegexBuilderTests/MotivationTests.swift @@ -310,8 +310,8 @@ extension RegexDSLTests { "CREDIT" "DEBIT" } - } transform: { (s: Substring) -> TransactionKind? in - TransactionKind(rawValue: String(s)) + } transform: { + TransactionKind(rawValue: String($0)) } OneOrMore(.whitespace) @@ -323,8 +323,8 @@ extension RegexDSLTests { Repeat(.digit, count: 2) Repeat(.digit, count: 2) Repeat(.digit, count: 4) - } transform: { (s: Substring) -> Date? in - Date(mmddyyyy: String(s)) + } transform: { + Date(mmddyyyy: String($0)) } OneOrMore(.whitespace) @@ -346,8 +346,8 @@ extension RegexDSLTests { OneOrMore(.digit) "." Repeat(.digit, count: 2) - } transform: { (s: Substring) -> Double? in - Double(s) + } transform: { + Double($0) } } diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 0dd050357..e560a80e3 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -1254,8 +1254,8 @@ class RegexDSLTests: XCTestCase { TryCapture(as: b) { "#" OneOrMore(.digit) - } transform: { (s: Substring) in - Int(s.dropFirst()) + } transform: { + Int($0.dropFirst()) } } a @@ -1272,14 +1272,14 @@ class RegexDSLTests: XCTestCase { do { let a = Reference(Substring.self) let b = Reference(Int.self) - let regex = Regex<(Substring, Substring, Int?, Int?, Substring?)> { + let regex = Regex { Capture("abc", as: a) ZeroOrMore { TryCapture(as: b) { "#" OneOrMore(.digit) - } transform: { (s: Substring) -> Int? in - Int(s.dropFirst()) + } transform: { + Int($0.dropFirst()) } } a From 1358fc0433072922c4ab51d041c79e129585fb15 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 14 Feb 2023 23:21:35 -0600 Subject: [PATCH 16/34] Use `some` syntax in variadics This supports a type checker fix after the change in how result builder closure parameters are type-checked. --- Sources/RegexBuilder/DSL.swift | 12 +- Sources/RegexBuilder/Variadics.swift | 2729 +++++++++-------- .../VariadicsGenerator.swift | 237 +- Tests/RegexBuilderTests/AlgorithmsTests.swift | 10 +- Tests/RegexBuilderTests/RegexDSLTests.swift | 6 +- Tests/RegexTests/AlgorithmsTests.swift | 22 +- 6 files changed, 1607 insertions(+), 1409 deletions(-) diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 680f3bd2f..90e0d25f6 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -15,9 +15,9 @@ @available(SwiftStdlib 5.7, *) extension Regex { /// Creates a regular expression using a RegexBuilder closure. - public init( - @RegexComponentBuilder _ content: () -> Content - ) where Content.RegexOutput == Output { + public init( + @RegexComponentBuilder _ content: () -> some RegexComponent + ) { self = content().regex } } @@ -91,9 +91,9 @@ public struct One: RegexComponent { public var regex: Regex /// Creates a regex component that matches the given component exactly once. - public init( - _ component: Component - ) where Component.RegexOutput == Output { + public init( + _ component: some RegexComponent + ) { self.regex = component.regex } } diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index f11727521..8f104eae0 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -13,12 +13,15 @@ @_spi(RegexBuilder) import _StringProcessing +// MARK: - Partial block (left arity 0) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1)> + ) -> Regex<(Substring, C1)> { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } @@ -26,9 +29,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2)> + ) -> Regex<(Substring, C1, C2)> { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } @@ -36,9 +40,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3)> + ) -> Regex<(Substring, C1, C2, C3)> { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } @@ -46,9 +51,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4)> + ) -> Regex<(Substring, C1, C2, C3, C4)> { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } @@ -56,9 +62,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5)> { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } @@ -66,9 +73,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5, C6)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } @@ -76,9 +84,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5, C6, C7)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } @@ -86,9 +95,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5, C6, C7, C8)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } @@ -96,9 +106,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } @@ -106,19 +117,23 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == W0, R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, next) } } +// MARK: - Partial block (left arity 1) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2)> + ) -> Regex<(Substring, C1, C2)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -126,9 +141,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3)> + ) -> Regex<(Substring, C1, C2, C3)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -136,9 +152,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4)> + ) -> Regex<(Substring, C1, C2, C3, C4)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -146,9 +163,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -156,9 +174,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5, C6)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -166,9 +185,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5, C6, C7)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -176,9 +196,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5, C6, C7, C8)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -186,9 +207,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -196,19 +218,23 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } } +// MARK: - Partial block (left arity 2) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3)> + ) -> Regex<(Substring, C1, C2, C3)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -216,9 +242,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4)> + ) -> Regex<(Substring, C1, C2, C3, C4)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -226,9 +253,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -236,9 +264,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5, C6)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -246,9 +275,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5, C6, C7)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -256,9 +286,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5, C6, C7, C8)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -266,9 +297,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5, C6, C7, C8, C9)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -276,19 +308,23 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9, C10) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5, C6, C7, C8, C9, C10)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } } +// MARK: - Partial block (left arity 3) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4)> + ) -> Regex<(Substring, C1, C2, C3, C4)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -296,9 +332,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -306,9 +343,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5, C6)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -316,9 +354,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5, C6, C7)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -326,9 +365,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5, C6, C7, C8)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -336,9 +376,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5, C6, C7, C8, C9)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -346,19 +387,23 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9, C10) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5, C6, C7, C8, C9, C10)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } } +// MARK: - Partial block (left arity 4) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -366,9 +411,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5, C6)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -376,9 +422,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5, C6, C7)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -386,9 +433,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5, C6, C7, C8)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -396,9 +444,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5, C6, C7, C8, C9)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -406,19 +455,23 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9, C10) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5, C6, C7, C8, C9, C10)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } } +// MARK: - Partial block (left arity 5) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent<(W1, C6)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -426,9 +479,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent<(W1, C6, C7)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -436,9 +490,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent<(W1, C6, C7, C8)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -446,9 +501,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent<(W1, C6, C7, C8, C9)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -456,19 +512,23 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9, C10) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent<(W1, C6, C7, C8, C9, C10)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } } +// MARK: - Partial block (left arity 6) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6)>, + next: some RegexComponent<(W1, C7)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -476,9 +536,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6)>, + next: some RegexComponent<(W1, C7, C8)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -486,9 +547,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6)>, + next: some RegexComponent<(W1, C7, C8, C9)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -496,19 +558,23 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9, C10) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6)>, + next: some RegexComponent<(W1, C7, C8, C9, C10)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } } +// MARK: - Partial block (left arity 7) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7)>, + next: some RegexComponent<(W1, C8)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -516,9 +582,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7)>, + next: some RegexComponent<(W1, C8, C9)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -526,19 +593,23 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9, C10) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7)>, + next: some RegexComponent<(W1, C8, C9, C10)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } } +// MARK: - Partial block (left arity 8) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7, C8)>, + next: some RegexComponent<(W1, C9)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } @@ -546,29 +617,36 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9, C10) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7, C8)>, + next: some RegexComponent<(W1, C9, C10)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } } +// MARK: - Partial block (left arity 9) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> where R0.RegexOutput == (W0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R1.RegexOutput == (W1, C10) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, + next: some RegexComponent<(W1, C10)> + ) -> Regex<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> { let factory = makeFactory() return factory.accumulate(accumulated, next) } } +// MARK: - Partial block (empty) + @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex where R0.RegexOutput == W0 { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent + ) -> Regex { let factory = makeFactory() return factory.accumulate(ignoringOutputTypeOf: accumulated, andAlso: next) } @@ -576,9 +654,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C0)> where R0.RegexOutput == (W0, C0) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C0)>, + next: some RegexComponent + ) -> Regex<(Substring, C0)> { let factory = makeFactory() return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } @@ -586,9 +665,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == (W0, C0, C1) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C0, C1)>, + next: some RegexComponent + ) -> Regex<(Substring, C0, C1)> { let factory = makeFactory() return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } @@ -596,9 +676,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0, C1, C2) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C0, C1, C2)>, + next: some RegexComponent + ) -> Regex<(Substring, C0, C1, C2)> { let factory = makeFactory() return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } @@ -606,9 +687,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1, C2, C3) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C0, C1, C2, C3)>, + next: some RegexComponent + ) -> Regex<(Substring, C0, C1, C2, C3)> { let factory = makeFactory() return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } @@ -616,9 +698,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C0, C1, C2, C3, C4)>, + next: some RegexComponent + ) -> Regex<(Substring, C0, C1, C2, C3, C4)> { let factory = makeFactory() return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } @@ -626,9 +709,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C0, C1, C2, C3, C4, C5)>, + next: some RegexComponent + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> { let factory = makeFactory() return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } @@ -636,9 +720,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C0, C1, C2, C3, C4, C5, C6)>, + next: some RegexComponent + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> { let factory = makeFactory() return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } @@ -646,9 +731,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C0, C1, C2, C3, C4, C5, C6, C7)>, + next: some RegexComponent + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> { let factory = makeFactory() return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } @@ -656,9 +742,10 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C0, C1, C2, C3, C4, C5, C6, C7, C8)>, + next: some RegexComponent + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> { let factory = makeFactory() return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } @@ -666,15 +753,18 @@ extension RegexComponentBuilder { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, + next: some RegexComponent + ) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return factory.accumulate(accumulated, ignoringOutputTypeOf: next) } } +// MARK: - Quantifiers (arity 0) + @available(SwiftStdlib 5.7, *) extension Optionally { /// Creates a regex component that matches the given component @@ -689,8 +779,8 @@ extension Optionally { /// `Regex`. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent, _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == Substring { let factory = makeFactory() @@ -713,9 +803,9 @@ extension Optionally { /// component. @_disfavoredOverload @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent ) where RegexOutput == Substring { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) @@ -725,9 +815,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex { + public static func buildLimitedAvailability( + _ component: some RegexComponent + ) -> Regex { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -746,8 +836,8 @@ extension ZeroOrMore { /// `Regex`. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent, _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == Substring { let factory = makeFactory() @@ -770,9 +860,9 @@ extension ZeroOrMore { /// component. @_disfavoredOverload @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent ) where RegexOutput == Substring { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) @@ -794,8 +884,8 @@ extension OneOrMore { /// `Regex`. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent, _ behavior: RegexRepetitionBehavior? = nil ) where RegexOutput == Substring { let factory = makeFactory() @@ -818,9 +908,9 @@ extension OneOrMore { /// component. @_disfavoredOverload @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent ) where RegexOutput == Substring { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) @@ -839,8 +929,8 @@ extension Repeat { /// be greater than or equal to zero. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent, count: Int ) where RegexOutput == Substring { precondition(count >= 0, "Must specify a positive count") @@ -858,9 +948,9 @@ extension Repeat { /// component to repeat. @_disfavoredOverload @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent ) where RegexOutput == Substring { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() @@ -881,11 +971,11 @@ extension Repeat { /// `Regex`. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == Substring, R.Bound == Int { + ) where RegexOutput == Substring { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == Substring, R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent + ) where RegexOutput == Substring { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, C1?) { let factory = makeFactory() self.init(factory.zeroOrOne(component, behavior)) } @@ -950,10 +1042,10 @@ extension Optionally { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)> + ) where RegexOutput == (Substring, C1?) { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) } @@ -962,9 +1054,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex<(Substring, C1?)> where Component.RegexOutput == (W, C1) { + public static func buildLimitedAvailability( + _ component: some RegexComponent<(W, C1)> + ) -> Regex<(Substring, C1?)> { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -982,10 +1074,10 @@ extension ZeroOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, C1?) { let factory = makeFactory() self.init(factory.zeroOrMore(component, behavior)) } @@ -1005,10 +1097,10 @@ extension ZeroOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)> + ) where RegexOutput == (Substring, C1?) { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) } @@ -1028,10 +1120,10 @@ extension OneOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1), Component.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, C1) { let factory = makeFactory() self.init(factory.oneOrMore(component, behavior)) } @@ -1051,10 +1143,10 @@ extension OneOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1), Component.RegexOutput == (W, C1) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)> + ) where RegexOutput == (Substring, C1) { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) } @@ -1071,10 +1163,10 @@ extension Repeat { /// - count: The number of times to repeat `component`. `count` must /// be greater than or equal to zero. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1)>, count: Int - ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, C1?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) @@ -1089,10 +1181,10 @@ extension Repeat { /// - componentBuilder: A builder closure that creates the regex /// component to repeat. @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)> + ) where RegexOutput == (Substring, C1?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, componentBuilder())) @@ -1111,11 +1203,11 @@ extension Repeat { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent<(W, C1)>, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1), R.Bound == Int { + ) where RegexOutput == (Substring, C1?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1), R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)> + ) where RegexOutput == (Substring, C1?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, C1?, C2?) { let factory = makeFactory() self.init(factory.zeroOrOne(component, behavior)) } @@ -1179,10 +1273,10 @@ extension Optionally { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)> + ) where RegexOutput == (Substring, C1?, C2?) { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) } @@ -1191,9 +1285,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex<(Substring, C1?, C2?)> where Component.RegexOutput == (W, C1, C2) { + public static func buildLimitedAvailability( + _ component: some RegexComponent<(W, C1, C2)> + ) -> Regex<(Substring, C1?, C2?)> { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -1211,10 +1305,10 @@ extension ZeroOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, C1?, C2?) { let factory = makeFactory() self.init(factory.zeroOrMore(component, behavior)) } @@ -1234,10 +1328,10 @@ extension ZeroOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)> + ) where RegexOutput == (Substring, C1?, C2?) { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) } @@ -1257,10 +1351,10 @@ extension OneOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1, C2), Component.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, C1, C2) { let factory = makeFactory() self.init(factory.oneOrMore(component, behavior)) } @@ -1280,10 +1374,10 @@ extension OneOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2), Component.RegexOutput == (W, C1, C2) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)> + ) where RegexOutput == (Substring, C1, C2) { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) } @@ -1300,10 +1394,10 @@ extension Repeat { /// - count: The number of times to repeat `component`. `count` must /// be greater than or equal to zero. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2)>, count: Int - ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, C1?, C2?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) @@ -1318,10 +1412,10 @@ extension Repeat { /// - componentBuilder: A builder closure that creates the regex /// component to repeat. @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)> + ) where RegexOutput == (Substring, C1?, C2?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, componentBuilder())) @@ -1340,11 +1434,11 @@ extension Repeat { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent<(W, C1, C2)>, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2), R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)> + ) where RegexOutput == (Substring, C1?, C2?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, C1?, C2?, C3?) { let factory = makeFactory() self.init(factory.zeroOrOne(component, behavior)) } @@ -1408,10 +1504,10 @@ extension Optionally { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)> + ) where RegexOutput == (Substring, C1?, C2?, C3?) { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) } @@ -1420,9 +1516,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex<(Substring, C1?, C2?, C3?)> where Component.RegexOutput == (W, C1, C2, C3) { + public static func buildLimitedAvailability( + _ component: some RegexComponent<(W, C1, C2, C3)> + ) -> Regex<(Substring, C1?, C2?, C3?)> { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -1440,10 +1536,10 @@ extension ZeroOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, C1?, C2?, C3?) { let factory = makeFactory() self.init(factory.zeroOrMore(component, behavior)) } @@ -1463,10 +1559,10 @@ extension ZeroOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)> + ) where RegexOutput == (Substring, C1?, C2?, C3?) { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) } @@ -1486,10 +1582,10 @@ extension OneOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1, C2, C3), Component.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, C1, C2, C3) { let factory = makeFactory() self.init(factory.oneOrMore(component, behavior)) } @@ -1509,10 +1605,10 @@ extension OneOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3), Component.RegexOutput == (W, C1, C2, C3) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)> + ) where RegexOutput == (Substring, C1, C2, C3) { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) } @@ -1529,10 +1625,10 @@ extension Repeat { /// - count: The number of times to repeat `component`. `count` must /// be greater than or equal to zero. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3)>, count: Int - ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, C1?, C2?, C3?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) @@ -1547,10 +1643,10 @@ extension Repeat { /// - componentBuilder: A builder closure that creates the regex /// component to repeat. @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)> + ) where RegexOutput == (Substring, C1?, C2?, C3?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, componentBuilder())) @@ -1569,11 +1665,11 @@ extension Repeat { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3)>, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3), R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)> + ) where RegexOutput == (Substring, C1?, C2?, C3?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?) { let factory = makeFactory() self.init(factory.zeroOrOne(component, behavior)) } @@ -1637,10 +1735,10 @@ extension Optionally { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?) { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) } @@ -1649,9 +1747,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex<(Substring, C1?, C2?, C3?, C4?)> where Component.RegexOutput == (W, C1, C2, C3, C4) { + public static func buildLimitedAvailability( + _ component: some RegexComponent<(W, C1, C2, C3, C4)> + ) -> Regex<(Substring, C1?, C2?, C3?, C4?)> { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -1669,10 +1767,10 @@ extension ZeroOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?) { let factory = makeFactory() self.init(factory.zeroOrMore(component, behavior)) } @@ -1692,10 +1790,10 @@ extension ZeroOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?) { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) } @@ -1715,10 +1813,10 @@ extension OneOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1, C2, C3, C4), Component.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.oneOrMore(component, behavior)) } @@ -1738,10 +1836,10 @@ extension OneOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4), Component.RegexOutput == (W, C1, C2, C3, C4) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)> + ) where RegexOutput == (Substring, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) } @@ -1758,10 +1856,10 @@ extension Repeat { /// - count: The number of times to repeat `component`. `count` must /// be greater than or equal to zero. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)>, count: Int - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) @@ -1776,10 +1874,10 @@ extension Repeat { /// - componentBuilder: A builder closure that creates the regex /// component to repeat. @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, componentBuilder())) @@ -1798,11 +1896,11 @@ extension Repeat { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)>, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4), R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?) { let factory = makeFactory() self.init(factory.zeroOrOne(component, behavior)) } @@ -1866,10 +1966,10 @@ extension Optionally { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?) { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) } @@ -1878,9 +1978,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + public static func buildLimitedAvailability( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?)> { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -1898,10 +1998,10 @@ extension ZeroOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?) { let factory = makeFactory() self.init(factory.zeroOrMore(component, behavior)) } @@ -1921,10 +2021,10 @@ extension ZeroOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?) { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) } @@ -1944,10 +2044,10 @@ extension OneOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.oneOrMore(component, behavior)) } @@ -1967,10 +2067,10 @@ extension OneOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) } @@ -1987,10 +2087,10 @@ extension Repeat { /// - count: The number of times to repeat `component`. `count` must /// be greater than or equal to zero. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)>, count: Int - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) @@ -2005,10 +2105,10 @@ extension Repeat { /// - componentBuilder: A builder closure that creates the regex /// component to repeat. @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, componentBuilder())) @@ -2027,11 +2127,11 @@ extension Repeat { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)>, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5), R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?) { let factory = makeFactory() self.init(factory.zeroOrOne(component, behavior)) } @@ -2095,10 +2197,10 @@ extension Optionally { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?) { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) } @@ -2107,9 +2209,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + public static func buildLimitedAvailability( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?)> { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -2127,10 +2229,10 @@ extension ZeroOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?) { let factory = makeFactory() self.init(factory.zeroOrMore(component, behavior)) } @@ -2150,10 +2252,10 @@ extension ZeroOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?) { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) } @@ -2173,10 +2275,10 @@ extension OneOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.oneOrMore(component, behavior)) } @@ -2196,10 +2298,10 @@ extension OneOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) } @@ -2216,10 +2318,10 @@ extension Repeat { /// - count: The number of times to repeat `component`. `count` must /// be greater than or equal to zero. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, count: Int - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) @@ -2234,10 +2336,10 @@ extension Repeat { /// - componentBuilder: A builder closure that creates the regex /// component to repeat. @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, componentBuilder())) @@ -2256,11 +2358,11 @@ extension Repeat { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6), R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?) { let factory = makeFactory() self.init(factory.zeroOrOne(component, behavior)) } @@ -2324,10 +2428,10 @@ extension Optionally { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?) { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) } @@ -2336,9 +2440,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + public static func buildLimitedAvailability( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -2356,10 +2460,10 @@ extension ZeroOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?) { let factory = makeFactory() self.init(factory.zeroOrMore(component, behavior)) } @@ -2379,10 +2483,10 @@ extension ZeroOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?) { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) } @@ -2402,10 +2506,10 @@ extension OneOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.oneOrMore(component, behavior)) } @@ -2425,10 +2529,10 @@ extension OneOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) } @@ -2445,10 +2549,10 @@ extension Repeat { /// - count: The number of times to repeat `component`. `count` must /// be greater than or equal to zero. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, count: Int - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) @@ -2463,10 +2567,10 @@ extension Repeat { /// - componentBuilder: A builder closure that creates the regex /// component to repeat. @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, componentBuilder())) @@ -2485,11 +2589,11 @@ extension Repeat { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?) { let factory = makeFactory() self.init(factory.zeroOrOne(component, behavior)) } @@ -2553,10 +2659,10 @@ extension Optionally { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?) { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) } @@ -2565,9 +2671,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + public static func buildLimitedAvailability( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -2585,10 +2691,10 @@ extension ZeroOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?) { let factory = makeFactory() self.init(factory.zeroOrMore(component, behavior)) } @@ -2608,10 +2714,10 @@ extension ZeroOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?) { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) } @@ -2631,10 +2737,10 @@ extension OneOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.oneOrMore(component, behavior)) } @@ -2654,10 +2760,10 @@ extension OneOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) } @@ -2674,10 +2780,10 @@ extension Repeat { /// - count: The number of times to repeat `component`. `count` must /// be greater than or equal to zero. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, count: Int - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) @@ -2692,10 +2798,10 @@ extension Repeat { /// - componentBuilder: A builder closure that creates the regex /// component to repeat. @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, componentBuilder())) @@ -2714,11 +2820,11 @@ extension Repeat { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) { let factory = makeFactory() self.init(factory.zeroOrOne(component, behavior)) } @@ -2782,10 +2890,10 @@ extension Optionally { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) } @@ -2794,9 +2902,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public static func buildLimitedAvailability( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -2814,10 +2922,10 @@ extension ZeroOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) { let factory = makeFactory() self.init(factory.zeroOrMore(component, behavior)) } @@ -2837,10 +2945,10 @@ extension ZeroOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) } @@ -2860,10 +2968,10 @@ extension OneOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.oneOrMore(component, behavior)) } @@ -2883,10 +2991,10 @@ extension OneOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) } @@ -2903,10 +3011,10 @@ extension Repeat { /// - count: The number of times to repeat `component`. `count` must /// be greater than or equal to zero. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, count: Int - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) @@ -2921,10 +3029,10 @@ extension Repeat { /// - componentBuilder: A builder closure that creates the regex /// component to repeat. @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, componentBuilder())) @@ -2943,11 +3051,11 @@ extension Repeat { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?) { let factory = makeFactory() self.init(factory.zeroOrOne(component, behavior)) } @@ -3011,10 +3121,10 @@ extension Optionally { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?) { let factory = makeFactory() self.init(factory.zeroOrOne(componentBuilder(), behavior)) } @@ -3023,9 +3133,9 @@ extension Optionally { @available(SwiftStdlib 5.7, *) extension RegexComponentBuilder { @_alwaysEmitIntoClient - public static func buildLimitedAvailability( - _ component: Component - ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?)> where Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + public static func buildLimitedAvailability( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) -> Regex<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?)> { let factory = makeFactory() return factory.zeroOrOne(component, nil) } @@ -3043,10 +3153,10 @@ extension ZeroOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?) { let factory = makeFactory() self.init(factory.zeroOrMore(component, behavior)) } @@ -3066,10 +3176,10 @@ extension ZeroOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?) { let factory = makeFactory() self.init(factory.zeroOrMore(componentBuilder(), behavior)) } @@ -3089,10 +3199,10 @@ extension OneOrMore { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.oneOrMore(component, behavior)) } @@ -3112,10 +3222,10 @@ extension OneOrMore { /// - componentBuilder: A builder closure that generates a regex /// component. @_alwaysEmitIntoClient - public init( + public init( _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.oneOrMore(componentBuilder(), behavior)) } @@ -3132,10 +3242,10 @@ extension Repeat { /// - count: The number of times to repeat `component`. `count` must /// be greater than or equal to zero. @_alwaysEmitIntoClient - public init( - _ component: Component, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, count: Int - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) @@ -3150,10 +3260,10 @@ extension Repeat { /// - componentBuilder: A builder closure that creates the regex /// component to repeat. @_alwaysEmitIntoClient - public init( + public init( count: Int, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, componentBuilder())) @@ -3172,11 +3282,11 @@ extension Repeat { /// `eager` by calling `repetitionBehavior(_:)` on the resulting /// `Regex`. @_alwaysEmitIntoClient - public init( - _ component: Component, - _ expression: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.Bound == Int { + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.Bound == Int { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ component: Component + public init( + _ component: some RegexComponent ) where RegexOutput == Substring { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) @@ -3230,8 +3342,8 @@ extension Local { @available(SwiftStdlib 5.7, *) @_disfavoredOverload @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent ) where RegexOutput == Substring { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) @@ -3245,9 +3357,9 @@ extension Local { /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - _ component: Component - ) where RegexOutput == (Substring, C1), Component.RegexOutput == (W, C1) { + public init( + _ component: some RegexComponent<(W, C1)> + ) where RegexOutput == (Substring, C1) { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) } @@ -3261,9 +3373,9 @@ extension Local { /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1), Component.RegexOutput == (W, C1) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)> + ) where RegexOutput == (Substring, C1) { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) } @@ -3276,9 +3388,9 @@ extension Local { /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - _ component: Component - ) where RegexOutput == (Substring, C1, C2), Component.RegexOutput == (W, C1, C2) { + public init( + _ component: some RegexComponent<(W, C1, C2)> + ) where RegexOutput == (Substring, C1, C2) { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) } @@ -3292,9 +3404,9 @@ extension Local { /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2), Component.RegexOutput == (W, C1, C2) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)> + ) where RegexOutput == (Substring, C1, C2) { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) } @@ -3307,9 +3419,9 @@ extension Local { /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - _ component: Component - ) where RegexOutput == (Substring, C1, C2, C3), Component.RegexOutput == (W, C1, C2, C3) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3)> + ) where RegexOutput == (Substring, C1, C2, C3) { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) } @@ -3323,9 +3435,9 @@ extension Local { /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3), Component.RegexOutput == (W, C1, C2, C3) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)> + ) where RegexOutput == (Substring, C1, C2, C3) { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) } @@ -3338,9 +3450,9 @@ extension Local { /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - _ component: Component - ) where RegexOutput == (Substring, C1, C2, C3, C4), Component.RegexOutput == (W, C1, C2, C3, C4) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)> + ) where RegexOutput == (Substring, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) } @@ -3354,9 +3466,9 @@ extension Local { /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4), Component.RegexOutput == (W, C1, C2, C3, C4) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)> + ) where RegexOutput == (Substring, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) } @@ -3369,9 +3481,9 @@ extension Local { /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - _ component: Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) } @@ -3385,9 +3497,9 @@ extension Local { /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) } @@ -3400,9 +3512,9 @@ extension Local { /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - _ component: Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) } @@ -3416,9 +3528,9 @@ extension Local { /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) } @@ -3431,9 +3543,9 @@ extension Local { /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - _ component: Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) } @@ -3447,9 +3559,9 @@ extension Local { /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) } @@ -3462,9 +3574,9 @@ extension Local { /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - _ component: Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) } @@ -3478,9 +3590,9 @@ extension Local { /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) } @@ -3493,9 +3605,9 @@ extension Local { /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - _ component: Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) } @@ -3509,9 +3621,9 @@ extension Local { /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) } @@ -3524,9 +3636,9 @@ extension Local { /// group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - _ component: Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.atomicNonCapturing(component)) } @@ -3540,19 +3652,22 @@ extension Local { /// regex component to wrap in an atomic group. @available(SwiftStdlib 5.7, *) @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> Component - ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) where RegexOutput == (Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.atomicNonCapturing(componentBuilder())) } } +// MARK: - Alternation builder (arity 0) + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf where R0: RegexComponent, R1: RegexComponent { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent + ) -> ChoiceOf { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3560,9 +3675,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1)> + ) -> ChoiceOf<(Substring, C1?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3570,9 +3686,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2)> + ) -> ChoiceOf<(Substring, C1?, C2?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3580,9 +3697,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3)> + ) -> ChoiceOf<(Substring, C1?, C2?, C3?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3590,9 +3708,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4)> + ) -> ChoiceOf<(Substring, C1?, C2?, C3?, C4?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3600,9 +3719,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5)> + ) -> ChoiceOf<(Substring, C1?, C2?, C3?, C4?, C5?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3610,9 +3730,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5, C6)> + ) -> ChoiceOf<(Substring, C1?, C2?, C3?, C4?, C5?, C6?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3620,9 +3741,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5, C6, C7)> + ) -> ChoiceOf<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3630,9 +3752,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5, C6, C7, C8)> + ) -> ChoiceOf<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3640,9 +3763,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) -> ChoiceOf<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3650,19 +3774,23 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R1.RegexOutput == (W1, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent, + next: some RegexComponent<(W1, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) -> ChoiceOf<(Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } } +// MARK: - Alternation builder (arity 1) + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent + ) -> ChoiceOf<(Substring, C1)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3670,9 +3798,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2)> + ) -> ChoiceOf<(Substring, C1, C2?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3680,9 +3809,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3)> + ) -> ChoiceOf<(Substring, C1, C2?, C3?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3690,9 +3820,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4)> + ) -> ChoiceOf<(Substring, C1, C2?, C3?, C4?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3700,9 +3831,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5)> + ) -> ChoiceOf<(Substring, C1, C2?, C3?, C4?, C5?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3710,9 +3842,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5, C6)> + ) -> ChoiceOf<(Substring, C1, C2?, C3?, C4?, C5?, C6?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3720,9 +3853,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5, C6, C7)> + ) -> ChoiceOf<(Substring, C1, C2?, C3?, C4?, C5?, C6?, C7?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3730,9 +3864,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5, C6, C7, C8)> + ) -> ChoiceOf<(Substring, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3740,9 +3875,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) -> ChoiceOf<(Substring, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3750,19 +3886,23 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0), R1.RegexOutput == (W1, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1)>, + next: some RegexComponent<(W1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) -> ChoiceOf<(Substring, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } } +// MARK: - Alternation builder (arity 2) + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent + ) -> ChoiceOf<(Substring, C1, C2)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3770,9 +3910,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3)> + ) -> ChoiceOf<(Substring, C1, C2, C3?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3780,9 +3921,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4)> + ) -> ChoiceOf<(Substring, C1, C2, C3?, C4?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3790,9 +3932,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5)> + ) -> ChoiceOf<(Substring, C1, C2, C3?, C4?, C5?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3800,9 +3943,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5, C6)> + ) -> ChoiceOf<(Substring, C1, C2, C3?, C4?, C5?, C6?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3810,9 +3954,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5, C6, C7)> + ) -> ChoiceOf<(Substring, C1, C2, C3?, C4?, C5?, C6?, C7?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3820,9 +3965,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5, C6, C7, C8)> + ) -> ChoiceOf<(Substring, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3830,9 +3976,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5, C6, C7, C8, C9)> + ) -> ChoiceOf<(Substring, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3840,19 +3987,23 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1), R1.RegexOutput == (W1, C2, C3, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2)>, + next: some RegexComponent<(W1, C3, C4, C5, C6, C7, C8, C9, C10)> + ) -> ChoiceOf<(Substring, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } } +// MARK: - Alternation builder (arity 3) + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent + ) -> ChoiceOf<(Substring, C1, C2, C3)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3860,9 +4011,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3870,9 +4022,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4?, C5?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3880,9 +4033,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5, C6)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4?, C5?, C6?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3890,9 +4044,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5, C6, C7)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4?, C5?, C6?, C7?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3900,9 +4055,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5, C6, C7, C8)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4?, C5?, C6?, C7?, C8?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3910,9 +4066,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5, C6, C7, C8, C9)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3920,19 +4077,23 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2), R1.RegexOutput == (W1, C3, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3)>, + next: some RegexComponent<(W1, C4, C5, C6, C7, C8, C9, C10)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?, C10?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } } +// MARK: - Alternation builder (arity 4) + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent + ) -> ChoiceOf<(Substring, C1, C2, C3, C4)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3940,9 +4101,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3950,9 +4112,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5, C6)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5?, C6?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3960,9 +4123,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5, C6, C7)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5?, C6?, C7?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3970,9 +4134,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5, C6, C7, C8)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5?, C6?, C7?, C8?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3980,9 +4145,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5, C6, C7, C8, C9)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -3990,19 +4156,23 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4?, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3), R1.RegexOutput == (W1, C4, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4)>, + next: some RegexComponent<(W1, C5, C6, C7, C8, C9, C10)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?, C10?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } } +// MARK: - Alternation builder (arity 5) + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4010,9 +4180,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent<(W1, C6)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4020,9 +4191,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent<(W1, C6, C7)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6?, C7?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4030,9 +4202,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent<(W1, C6, C7, C8)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6?, C7?, C8?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4040,9 +4213,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent<(W1, C6, C7, C8, C9)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4050,19 +4224,23 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5?, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4), R1.RegexOutput == (W1, C5, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5)>, + next: some RegexComponent<(W1, C6, C7, C8, C9, C10)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?, C10?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } } +// MARK: - Alternation builder (arity 6) + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6)>, + next: some RegexComponent + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4070,9 +4248,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6)>, + next: some RegexComponent<(W1, C7)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4080,9 +4259,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6)>, + next: some RegexComponent<(W1, C7, C8)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7?, C8?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4090,9 +4270,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6)>, + next: some RegexComponent<(W1, C7, C8, C9)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4100,19 +4281,23 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6?, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5), R1.RegexOutput == (W1, C6, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6)>, + next: some RegexComponent<(W1, C7, C8, C9, C10)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?, C10?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } } +// MARK: - Alternation builder (arity 7) + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7)>, + next: some RegexComponent + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4120,9 +4305,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7)>, + next: some RegexComponent<(W1, C8)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7, C8?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4130,9 +4316,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7)>, + next: some RegexComponent<(W1, C8, C9)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7, C8?, C9?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4140,19 +4327,23 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7?, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6), R1.RegexOutput == (W1, C7, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7)>, + next: some RegexComponent<(W1, C8, C9, C10)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7, C8?, C9?, C10?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } } +// MARK: - Alternation builder (arity 8) + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7, C8)>, + next: some RegexComponent + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7, C8)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4160,9 +4351,10 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7, C8)>, + next: some RegexComponent<(W1, C9)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4170,19 +4362,23 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8?, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7), R1.RegexOutput == (W1, C8, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7, C8)>, + next: some RegexComponent<(W1, C9, C10)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9?, C10?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } } +// MARK: - Alternation builder (arity 9) + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, + next: some RegexComponent + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -4190,13 +4386,16 @@ extension AlternationBuilder { @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient - public static func buildPartialBlock( - accumulated: R0, next: R1 - ) -> ChoiceOf<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9?)> where R0: RegexComponent, R1: RegexComponent, R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8), R1.RegexOutput == (W1, C9) { + public static func buildPartialBlock( + accumulated: some RegexComponent<(W0, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, + next: some RegexComponent<(W1, C10)> + ) -> ChoiceOf<(Substring, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10?)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } } +// MARK: - Alternation builder buildBlock + @available(SwiftStdlib 5.7, *) extension AlternationBuilder { @_alwaysEmitIntoClient @@ -4277,7 +4476,7 @@ extension AlternationBuilder { return .init(factory.orderedChoice(regex)) } } -// MARK: - Non-builder capture arity 0 +// MARK: - Non-builder capture (arity 0) @available(SwiftStdlib 5.7, *) extension Capture { @@ -4286,9 +4485,9 @@ extension Capture { /// - Parameter component: The regex component to capture. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W), R.RegexOutput == W { + public init( + _ component: some RegexComponent + ) where RegexOutput == (Substring, W) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -4302,9 +4501,10 @@ extension Capture { /// `component`. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W), R.RegexOutput == W { + public init( + _ component: some RegexComponent, + as reference: Reference + ) where RegexOutput == (Substring, W) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -4320,10 +4520,10 @@ extension Capture { /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { + ) where RegexOutput == (Substring, NewCapture) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -4341,11 +4541,11 @@ extension Capture { /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { + ) where RegexOutput == (Substring, NewCapture) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -4365,10 +4565,10 @@ extension TryCapture { /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { + ) where RegexOutput == (Substring, NewCapture) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -4387,17 +4587,16 @@ extension TryCapture { /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { + ) where RegexOutput == (Substring, NewCapture) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 0 +// MARK: - Builder capture (arity 0) @available(SwiftStdlib 5.7, *) extension Capture { @@ -4407,9 +4606,9 @@ extension Capture { /// regex component to capture. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W), R.RegexOutput == W { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent + ) where RegexOutput == (Substring, W) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -4424,10 +4623,10 @@ extension Capture { /// component to capture. @_disfavoredOverload @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W), R.RegexOutput == W { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent + ) where RegexOutput == (Substring, W) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -4444,10 +4643,10 @@ extension Capture { /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { + ) where RegexOutput == (Substring, NewCapture) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -4466,11 +4665,11 @@ extension Capture { /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { + ) where RegexOutput == (Substring, NewCapture) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -4491,10 +4690,10 @@ extension TryCapture { /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { + ) where RegexOutput == (Substring, NewCapture) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -4514,17 +4713,17 @@ extension TryCapture { /// to the caller. @_disfavoredOverload @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture), R.RegexOutput == W { + ) where RegexOutput == (Substring, NewCapture) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } -// MARK: - Non-builder capture arity 1 +// MARK: - Non-builder capture (arity 1) @available(SwiftStdlib 5.7, *) extension Capture { @@ -4532,9 +4731,9 @@ extension Capture { /// /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { + public init( + _ component: some RegexComponent<(W, C1)> + ) where RegexOutput == (Substring, W, C1) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -4547,9 +4746,10 @@ extension Capture { /// - reference: The reference to use for anything captured by /// `component`. @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { + public init( + _ component: some RegexComponent<(W, C1)>, + as reference: Reference + ) where RegexOutput == (Substring, W, C1) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -4564,10 +4764,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, NewCapture, C1) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -4584,11 +4784,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, NewCapture, C1) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -4607,10 +4807,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, NewCapture, C1) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -4628,17 +4828,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, NewCapture, C1) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 1 +// MARK: - Builder capture (arity 1) @available(SwiftStdlib 5.7, *) extension Capture { @@ -4647,9 +4846,9 @@ extension Capture { /// - Parameter componentBuilder: A builder closure that generates a /// regex component to capture. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)> + ) where RegexOutput == (Substring, W, C1) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -4663,10 +4862,10 @@ extension Capture { /// - componentBuilder: A builder closure that generates a regex /// component to capture. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1), R.RegexOutput == (W, C1) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)> + ) where RegexOutput == (Substring, W, C1) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -4682,10 +4881,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, NewCapture, C1) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -4703,11 +4902,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, NewCapture, C1) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -4727,10 +4926,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, NewCapture, C1) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -4749,17 +4948,17 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1), R.RegexOutput == (W, C1) { + ) where RegexOutput == (Substring, NewCapture, C1) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } -// MARK: - Non-builder capture arity 2 +// MARK: - Non-builder capture (arity 2) @available(SwiftStdlib 5.7, *) extension Capture { @@ -4767,9 +4966,9 @@ extension Capture { /// /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { + public init( + _ component: some RegexComponent<(W, C1, C2)> + ) where RegexOutput == (Substring, W, C1, C2) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -4782,9 +4981,10 @@ extension Capture { /// - reference: The reference to use for anything captured by /// `component`. @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { + public init( + _ component: some RegexComponent<(W, C1, C2)>, + as reference: Reference + ) where RegexOutput == (Substring, W, C1, C2) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -4799,10 +4999,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -4819,11 +5019,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -4842,10 +5042,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -4863,17 +5063,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 2 +// MARK: - Builder capture (arity 2) @available(SwiftStdlib 5.7, *) extension Capture { @@ -4882,9 +5081,9 @@ extension Capture { /// - Parameter componentBuilder: A builder closure that generates a /// regex component to capture. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)> + ) where RegexOutput == (Substring, W, C1, C2) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -4898,10 +5097,10 @@ extension Capture { /// - componentBuilder: A builder closure that generates a regex /// component to capture. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2), R.RegexOutput == (W, C1, C2) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)> + ) where RegexOutput == (Substring, W, C1, C2) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -4917,10 +5116,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -4938,11 +5137,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -4962,10 +5161,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -4984,17 +5183,17 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2), R.RegexOutput == (W, C1, C2) { + ) where RegexOutput == (Substring, NewCapture, C1, C2) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } -// MARK: - Non-builder capture arity 3 +// MARK: - Non-builder capture (arity 3) @available(SwiftStdlib 5.7, *) extension Capture { @@ -5002,9 +5201,9 @@ extension Capture { /// /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3)> + ) where RegexOutput == (Substring, W, C1, C2, C3) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -5017,9 +5216,10 @@ extension Capture { /// - reference: The reference to use for anything captured by /// `component`. @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3)>, + as reference: Reference + ) where RegexOutput == (Substring, W, C1, C2, C3) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -5034,10 +5234,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -5054,11 +5254,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -5077,10 +5277,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -5098,17 +5298,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 3 +// MARK: - Builder capture (arity 3) @available(SwiftStdlib 5.7, *) extension Capture { @@ -5117,9 +5316,9 @@ extension Capture { /// - Parameter componentBuilder: A builder closure that generates a /// regex component to capture. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)> + ) where RegexOutput == (Substring, W, C1, C2, C3) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -5133,10 +5332,10 @@ extension Capture { /// - componentBuilder: A builder closure that generates a regex /// component to capture. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)> + ) where RegexOutput == (Substring, W, C1, C2, C3) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -5152,10 +5351,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -5173,11 +5372,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -5197,10 +5396,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -5219,17 +5418,17 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3), R.RegexOutput == (W, C1, C2, C3) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } -// MARK: - Non-builder capture arity 4 +// MARK: - Non-builder capture (arity 4) @available(SwiftStdlib 5.7, *) extension Capture { @@ -5237,9 +5436,9 @@ extension Capture { /// /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -5252,9 +5451,10 @@ extension Capture { /// - reference: The reference to use for anything captured by /// `component`. @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)>, + as reference: Reference + ) where RegexOutput == (Substring, W, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -5269,10 +5469,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -5289,11 +5489,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -5312,10 +5512,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -5333,17 +5533,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 4 +// MARK: - Builder capture (arity 4) @available(SwiftStdlib 5.7, *) extension Capture { @@ -5352,9 +5551,9 @@ extension Capture { /// - Parameter componentBuilder: A builder closure that generates a /// regex component to capture. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -5368,10 +5567,10 @@ extension Capture { /// - componentBuilder: A builder closure that generates a regex /// component to capture. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -5387,10 +5586,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -5408,11 +5607,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -5432,10 +5631,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -5454,17 +5653,17 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4), R.RegexOutput == (W, C1, C2, C3, C4) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } -// MARK: - Non-builder capture arity 5 +// MARK: - Non-builder capture (arity 5) @available(SwiftStdlib 5.7, *) extension Capture { @@ -5472,9 +5671,9 @@ extension Capture { /// /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -5487,9 +5686,10 @@ extension Capture { /// - reference: The reference to use for anything captured by /// `component`. @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)>, + as reference: Reference + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -5504,10 +5704,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -5524,11 +5724,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -5547,10 +5747,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -5568,17 +5768,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 5 +// MARK: - Builder capture (arity 5) @available(SwiftStdlib 5.7, *) extension Capture { @@ -5587,9 +5786,9 @@ extension Capture { /// - Parameter componentBuilder: A builder closure that generates a /// regex component to capture. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -5603,10 +5802,10 @@ extension Capture { /// - componentBuilder: A builder closure that generates a regex /// component to capture. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -5622,10 +5821,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -5643,11 +5842,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -5667,10 +5866,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -5689,17 +5888,17 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5), R.RegexOutput == (W, C1, C2, C3, C4, C5) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } -// MARK: - Non-builder capture arity 6 +// MARK: - Non-builder capture (arity 6) @available(SwiftStdlib 5.7, *) extension Capture { @@ -5707,9 +5906,9 @@ extension Capture { /// /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -5722,9 +5921,10 @@ extension Capture { /// - reference: The reference to use for anything captured by /// `component`. @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, + as reference: Reference + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -5739,10 +5939,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -5759,11 +5959,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -5782,10 +5982,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -5803,17 +6003,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 6 +// MARK: - Builder capture (arity 6) @available(SwiftStdlib 5.7, *) extension Capture { @@ -5822,9 +6021,9 @@ extension Capture { /// - Parameter componentBuilder: A builder closure that generates a /// regex component to capture. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -5838,10 +6037,10 @@ extension Capture { /// - componentBuilder: A builder closure that generates a regex /// component to capture. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -5857,10 +6056,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -5878,11 +6077,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -5902,10 +6101,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -5924,17 +6123,17 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } -// MARK: - Non-builder capture arity 7 +// MARK: - Non-builder capture (arity 7) @available(SwiftStdlib 5.7, *) extension Capture { @@ -5942,9 +6141,9 @@ extension Capture { /// /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -5957,9 +6156,10 @@ extension Capture { /// - reference: The reference to use for anything captured by /// `component`. @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, + as reference: Reference + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -5974,10 +6174,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -5994,11 +6194,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -6017,10 +6217,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -6038,17 +6238,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 7 +// MARK: - Builder capture (arity 7) @available(SwiftStdlib 5.7, *) extension Capture { @@ -6057,9 +6256,9 @@ extension Capture { /// - Parameter componentBuilder: A builder closure that generates a /// regex component to capture. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -6073,10 +6272,10 @@ extension Capture { /// - componentBuilder: A builder closure that generates a regex /// component to capture. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -6092,10 +6291,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -6113,11 +6312,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -6137,10 +6336,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -6159,17 +6358,17 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } -// MARK: - Non-builder capture arity 8 +// MARK: - Non-builder capture (arity 8) @available(SwiftStdlib 5.7, *) extension Capture { @@ -6177,9 +6376,9 @@ extension Capture { /// /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -6192,9 +6391,10 @@ extension Capture { /// - reference: The reference to use for anything captured by /// `component`. @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, + as reference: Reference + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -6209,10 +6409,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -6229,11 +6429,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -6252,10 +6452,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -6273,17 +6473,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 8 +// MARK: - Builder capture (arity 8) @available(SwiftStdlib 5.7, *) extension Capture { @@ -6292,9 +6491,9 @@ extension Capture { /// - Parameter componentBuilder: A builder closure that generates a /// regex component to capture. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -6308,10 +6507,10 @@ extension Capture { /// - componentBuilder: A builder closure that generates a regex /// component to capture. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -6327,10 +6526,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -6348,11 +6547,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -6372,10 +6571,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -6394,17 +6593,17 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } -// MARK: - Non-builder capture arity 9 +// MARK: - Non-builder capture (arity 9) @available(SwiftStdlib 5.7, *) extension Capture { @@ -6412,9 +6611,9 @@ extension Capture { /// /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -6427,9 +6626,10 @@ extension Capture { /// - reference: The reference to use for anything captured by /// `component`. @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, + as reference: Reference + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -6444,10 +6644,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -6464,11 +6664,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -6487,10 +6687,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -6508,17 +6708,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 9 +// MARK: - Builder capture (arity 9) @available(SwiftStdlib 5.7, *) extension Capture { @@ -6527,9 +6726,9 @@ extension Capture { /// - Parameter componentBuilder: A builder closure that generates a /// regex component to capture. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -6543,10 +6742,10 @@ extension Capture { /// - componentBuilder: A builder closure that generates a regex /// component to capture. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -6562,10 +6761,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -6583,11 +6782,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -6607,10 +6806,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -6629,17 +6828,17 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } -// MARK: - Non-builder capture arity 10 +// MARK: - Non-builder capture (arity 10) @available(SwiftStdlib 5.7, *) extension Capture { @@ -6647,9 +6846,9 @@ extension Capture { /// /// - Parameter component: The regex component to capture. @_alwaysEmitIntoClient - public init( - _ component: R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.capture(component)) } @@ -6662,9 +6861,10 @@ extension Capture { /// - reference: The reference to use for anything captured by /// `component`. @_alwaysEmitIntoClient - public init( - _ component: R, as reference: Reference - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, + as reference: Reference + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) } @@ -6679,10 +6879,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.capture(component, nil, transform)) } @@ -6699,11 +6899,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.capture(component, reference._raw, transform)) } @@ -6722,10 +6922,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.captureOptional(component, nil, transform)) } @@ -6743,17 +6943,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - _ component: R, + public init( + _ component: some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.captureOptional(component, reference._raw, transform)) } } - -// MARK: - Builder capture arity 10 +// MARK: - Builder capture (arity 10) @available(SwiftStdlib 5.7, *) extension Capture { @@ -6762,9 +6961,9 @@ extension Capture { /// - Parameter componentBuilder: A builder closure that generates a /// regex component to capture. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) } @@ -6778,10 +6977,10 @@ extension Capture { /// - componentBuilder: A builder closure that generates a regex /// component to capture. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R - ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)> + ) where RegexOutput == (Substring, W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) } @@ -6797,10 +6996,10 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), nil, transform)) } @@ -6818,11 +7017,11 @@ extension Capture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, transform: @escaping (W) throws -> NewCapture - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw, transform)) } @@ -6842,10 +7041,10 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( - @RegexComponentBuilder _ componentBuilder: () -> R, + public init( + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), nil, transform)) } @@ -6864,12 +7063,16 @@ extension TryCapture { /// throws an error, matching is abandoned and the error is returned /// to the caller. @_alwaysEmitIntoClient - public init( + public init( as reference: Reference, - @RegexComponentBuilder _ componentBuilder: () -> R, + @RegexComponentBuilder _ componentBuilder: () -> some RegexComponent<(W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)>, transform: @escaping (W) throws -> NewCapture? - ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10), R.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { + ) where RegexOutput == (Substring, NewCapture, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { let factory = makeFactory() self.init(factory.captureOptional(componentBuilder(), reference._raw, transform)) } } + + + +// END AUTO-GENERATED CONTENT diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index 42673ccfd..91f1682dd 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -73,6 +73,10 @@ func output(_ content: String) { print(content, terminator: "") } +func outputMark(_ content: String) { + print("// MARK: - \(content)\n") +} + func outputForEach( _ elements: C, separator: String? = nil, @@ -148,13 +152,15 @@ struct VariadicsGenerator: ParsableCommand { log("Generating concatenation overloads...") for (leftArity, rightArity) in Permutations(totalArity: maxArity) { - guard rightArity != 0 else { + if rightArity == 0 { + outputMark("Partial block (left arity \(leftArity))") continue } log(" Left arity: \(leftArity) Right arity: \(rightArity)") emitConcatenation(leftArity: leftArity, rightArity: rightArity) } + outputMark("Partial block (empty)") for arity in 0...maxArity { emitConcatenationWithEmpty(leftArity: arity) } @@ -163,6 +169,7 @@ struct VariadicsGenerator: ParsableCommand { log("Generating quantifiers...") for arity in 0...maxArity { + outputMark("Quantifiers (arity \(arity))") log(" Arity \(arity): ", terminator: "") for kind in QuantifierKind.allCases { log("\(kind.rawValue) ", terminator: "") @@ -174,6 +181,7 @@ struct VariadicsGenerator: ParsableCommand { } log("Generating atomic groups...") + outputMark("Atomic groups") for arity in 0...maxArity { log(" Arity \(arity): ", terminator: "") emitAtomicGroup(arity: arity) @@ -182,11 +190,15 @@ struct VariadicsGenerator: ParsableCommand { log("Generating alternation overloads...") for (leftArity, rightArity) in Permutations(totalArity: maxArity) { + if rightArity == 0 { + outputMark("Alternation builder (arity \(leftArity))") + } log(" Left arity: \(leftArity) Right arity: \(rightArity)") emitAlternation(leftArity: leftArity, rightArity: rightArity) } log("Generating 'AlternationBuilder.buildBlock(_:)' overloads...") + outputMark("Alternation builder buildBlock") for arity in 1...maxArity { log(" Capture arity: \(arity)") emitUnaryAlternationBuildBlock(arity: arity) @@ -217,31 +229,16 @@ struct VariadicsGenerator: ParsableCommand { let genericParams: String = { var result = "W0, W1, " result += captureTypeList(leftArity+rightArity) - result += ", R0: \(regexComponentProtocolName), R1: \(regexComponentProtocolName)" return result }() // Emit concatenation type declaration. - - let whereClause: String = { - var result = " where R0.\(outputAssociatedTypeName) == " - if leftArity == 0 { - result += "W0" - } else { - result += "(W0, " - result += captureTypeList(leftArity) - result += ")" - } - result += ", R1.\(outputAssociatedTypeName) == " - if rightArity == 0 { - result += "W1" - } else { - result += "(W1, " - result += captureTypeList(leftArity+rightArity, lowerBound: leftArity) - result += ")" - } - return result - }() + let leftOutputType = leftArity == 0 + ? "W0" + : "(W0, \(captureTypeList(leftArity)))" + let rightOutputType = rightArity == 0 + ? "W1" + : "(W1, \(captureTypeList(leftArity+rightArity, lowerBound: leftArity)))" let matchType: String = { if leftArity+rightArity == 0 { @@ -259,8 +256,9 @@ struct VariadicsGenerator: ParsableCommand { extension \(concatBuilderName) { @_alwaysEmitIntoClient public static func buildPartialBlock<\(genericParams)>( - accumulated: R0, next: R1 - ) -> \(regexTypeName)<\(matchType)> \(whereClause) { + accumulated: some RegexComponent<\(leftOutputType)>, + next: some RegexComponent<\(rightOutputType)> + ) -> \(regexTypeName)<\(matchType)> { let factory = makeFactory() """) @@ -294,31 +292,34 @@ struct VariadicsGenerator: ParsableCommand { ", C\($0)" } output(""" - , R0: \(regexComponentProtocolName), R1: \(regexComponentProtocolName)>( - accumulated: R0, next: R1 - ) -> \(regexTypeName)< + >( + accumulated: some \(regexComponentProtocolName)< """) if leftArity == 0 { - output(baseMatchTypeName) + output("W0") } else { - output("(\(baseMatchTypeName)") + output("(W0") outputForEach(0.. where R0.\(outputAssociatedTypeName) == ") + output(""" + >, + next: some \(regexComponentProtocolName) + ) -> \(regexTypeName)< + """) if leftArity == 0 { - output("W0") + output(baseMatchTypeName) } else { - output("(W0") + output("(\(baseMatchTypeName)") outputForEach(0.. { let factory = makeFactory() """) @@ -380,30 +381,25 @@ struct VariadicsGenerator: ParsableCommand { } struct QuantifierParameters { + var arity: Int var disfavored: String var genericParams: String var whereClauseForInit: String - var whereClause: String var quantifiedCaptures: String var matchType: String - var repeatingWhereClause: String { - whereClauseForInit.isEmpty - ? "where R.Bound == Int" - : whereClauseForInit + ", R.Bound == Int" - } - init(kind: QuantifierKind, arity: Int) { + self.arity = arity self.disfavored = arity == 0 ? " @_disfavoredOverload\n" : "" self.genericParams = { var result = "" if arity > 0 { result += "W, " result += captureTypeList(arity) - result += ", " } - result += "Component: \(regexComponentProtocolName)" - return result + return result.isEmpty + ? "" + : "<\(result)>" }() let capturesJoined = captureTypeList(arity) @@ -418,10 +414,11 @@ struct VariadicsGenerator: ParsableCommand { self.matchType = arity == 0 ? baseMatchTypeName : "(\(baseMatchTypeName), \(quantifiedCaptures))" - self.whereClauseForInit = "where \(outputAssociatedTypeName) == \(matchType)" + - (arity == 0 ? "" : ", Component.\(outputAssociatedTypeName) == (W, \(capturesJoined))") - self.whereClause = arity == 0 ? "" : - "where Component.\(outputAssociatedTypeName) == (W, \(capturesJoined))" + self.whereClauseForInit = "where \(outputAssociatedTypeName) == \(matchType)" + } + + var primaryAssociatedType: String { + arity == 0 ? "" : "<(W, \(captureTypeList(arity)))>" } } @@ -442,8 +439,8 @@ struct VariadicsGenerator: ParsableCommand { /// `Regex`. \(params.disfavored)\ @_alwaysEmitIntoClient - public init<\(params.genericParams)>( - _ component: Component, + public init\(params.genericParams)( + _ component: some RegexComponent\(params.primaryAssociatedType), _ behavior: RegexRepetitionBehavior? = nil ) \(params.whereClauseForInit) { let factory = makeFactory() @@ -465,9 +462,9 @@ struct VariadicsGenerator: ParsableCommand { /// component. \(params.disfavored)\ @_alwaysEmitIntoClient - public init<\(params.genericParams)>( + public init\(params.genericParams)( _ behavior: RegexRepetitionBehavior? = nil, - @\(concatBuilderName) _ componentBuilder: () -> Component + @\(concatBuilderName) _ componentBuilder: () -> some RegexComponent\(params.primaryAssociatedType) ) \(params.whereClauseForInit) { let factory = makeFactory() self.init(factory.\(kind.astQuantifierAmount)(componentBuilder(), behavior)) @@ -479,9 +476,9 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) extension \(concatBuilderName) { @_alwaysEmitIntoClient - public static func buildLimitedAvailability<\(params.genericParams)>( - _ component: Component - ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { + public static func buildLimitedAvailability\(params.genericParams)( + _ component: some RegexComponent\(params.primaryAssociatedType) + ) -> \(regexTypeName)<\(params.matchType)> { let factory = makeFactory() return factory.\(kind.astQuantifierAmount)(component, nil) } @@ -505,19 +502,17 @@ struct VariadicsGenerator: ParsableCommand { let genericParams: String = { var result = "" if arity > 0 { - result += "W, " + result += "( - _ component: Component + public init\(genericParams)( + _ component: some RegexComponent\(arity == 0 ? "" : "<(W, \(capturesJoined))>") ) \(whereClauseForInit) { let factory = makeFactory() self.init(factory.atomicNonCapturing(\(node(builder: false)))) @@ -546,8 +541,8 @@ struct VariadicsGenerator: ParsableCommand { \(defaultAvailableAttr) \(disfavored)\ @_alwaysEmitIntoClient - public init<\(genericParams)>( - @\(concatBuilderName) _ componentBuilder: () -> Component + public init\(genericParams)( + @\(concatBuilderName) _ componentBuilder: () -> some RegexComponent\(arity == 0 ? "" : "<(W, \(capturesJoined))>") ) \(whereClauseForInit) { let factory = makeFactory() self.init(factory.atomicNonCapturing(\(node(builder: true)))) @@ -577,8 +572,8 @@ struct VariadicsGenerator: ParsableCommand { /// be greater than or equal to zero. \(params.disfavored)\ @_alwaysEmitIntoClient - public init<\(params.genericParams)>( - _ component: Component, + public init\(params.genericParams)( + _ component: some RegexComponent\(params.primaryAssociatedType), count: Int ) \(params.whereClauseForInit) { precondition(count >= 0, "Must specify a positive count") @@ -596,9 +591,9 @@ struct VariadicsGenerator: ParsableCommand { /// component to repeat. \(params.disfavored)\ @_alwaysEmitIntoClient - public init<\(params.genericParams)>( + public init\(params.genericParams)( count: Int, - @\(concatBuilderName) _ componentBuilder: () -> Component + @\(concatBuilderName) _ componentBuilder: () -> some RegexComponent\(params.primaryAssociatedType) ) \(params.whereClauseForInit) { precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() @@ -619,11 +614,11 @@ struct VariadicsGenerator: ParsableCommand { /// `Regex`. \(params.disfavored)\ @_alwaysEmitIntoClient - public init<\(params.genericParams), R: RangeExpression>( - _ component: Component, - _ expression: R, + public init\(params.genericParams)( + _ component: some RegexComponent\(params.primaryAssociatedType), + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil - ) \(params.repeatingWhereClause) { + ) \(params.whereClauseForInit) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0..( - _ expression: R, + public init\(params.genericParams)( + _ expression: some RangeExpression, _ behavior: RegexRepetitionBehavior? = nil, - @\(concatBuilderName) _ componentBuilder: () -> Component - ) \(params.repeatingWhereClause) { + @\(concatBuilderName) _ componentBuilder: () -> some RegexComponent\(params.primaryAssociatedType) + ) \(params.whereClauseForInit) { let factory = makeFactory() self.init(factory.repeating(expression.relative(to: 0.. 0 { - result += ", R0.\(outputAssociatedTypeName) == (W0, \((0.. 0 { - result += ", R1.\(outputAssociatedTypeName) == (W1, \((leftArity.." + let resultCaptures: String = { - var result = (0.. 0, rightArity > 0 { result += ", " } - result += (leftArity..( - accumulated: R0, next: R1 - ) -> ChoiceOf<\(matchType)> \(whereClause) { + public static func buildPartialBlock\(genericParams)( + accumulated: some RegexComponent\(leftGenParams.isEmpty ? "" : "<(\(leftGenParams))>"), + next: some RegexComponent\(rightGenParams.isEmpty ? "" : "<(\(rightGenParams))>") + ) -> ChoiceOf<\(matchType)> { let factory = makeFactory() return .init(factory.accumulateAlternation(accumulated, next)) } @@ -739,8 +727,8 @@ struct VariadicsGenerator: ParsableCommand { func emitCapture(arity: Int) { let disfavored = arity == 0 ? " @_disfavoredOverload\n" : "" let genericParams = arity == 0 - ? "R: \(regexComponentProtocolName), W" - : "R: \(regexComponentProtocolName), W, " + captureTypeList(arity) + ? "W" + : "W, " + captureTypeList(arity) let matchType = arity == 0 ? "W" : "(W, " + captureTypeList(arity) + ")" @@ -751,11 +739,10 @@ struct VariadicsGenerator: ParsableCommand { } let rawNewMatchType = newMatchType(newCaptureType: "W") let transformedNewMatchType = newMatchType(newCaptureType: "NewCapture") - let whereClauseRaw = "where \(outputAssociatedTypeName) == \(rawNewMatchType), R.\(outputAssociatedTypeName) == \(matchType)" - let whereClauseTransformed = "where \(outputAssociatedTypeName) == \(transformedNewMatchType), R.\(outputAssociatedTypeName) == \(matchType)" + let whereClauseRaw = "where \(outputAssociatedTypeName) == \(rawNewMatchType)" + let whereClauseTransformed = "where \(outputAssociatedTypeName) == \(transformedNewMatchType)" + outputMark("Non-builder capture (arity \(arity))") output(""" - // MARK: - Non-builder capture arity \(arity) - \(defaultAvailableAttr) extension Capture { /// Creates a capture for the given component. @@ -764,7 +751,7 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams)>( - _ component: R + _ component: some RegexComponent<\(matchType)> ) \(whereClauseRaw) { let factory = makeFactory() self.init(factory.capture(component)) @@ -780,7 +767,8 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams)>( - _ component: R, as reference: Reference + _ component: some RegexComponent<\(matchType)>, + as reference: Reference ) \(whereClauseRaw) { let factory = makeFactory() self.init(factory.capture(component, reference._raw)) @@ -798,7 +786,7 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( - _ component: R, + _ component: some RegexComponent<\(matchType)>, transform: @escaping (W) throws -> NewCapture ) \(whereClauseTransformed) { let factory = makeFactory() @@ -819,7 +807,7 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( - _ component: R, + _ component: some RegexComponent<\(matchType)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture ) \(whereClauseTransformed) { @@ -843,7 +831,7 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( - _ component: R, + _ component: some RegexComponent<\(matchType)>, transform: @escaping (W) throws -> NewCapture? ) \(whereClauseTransformed) { let factory = makeFactory() @@ -865,7 +853,7 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( - _ component: R, + _ component: some RegexComponent<\(matchType)>, as reference: Reference, transform: @escaping (W) throws -> NewCapture? ) \(whereClauseTransformed) { @@ -873,9 +861,10 @@ struct VariadicsGenerator: ParsableCommand { self.init(factory.captureOptional(component, reference._raw, transform)) } } - - // MARK: - Builder capture arity \(arity) - + + """) + outputMark("Builder capture (arity \(arity))") + output(""" \(defaultAvailableAttr) extension Capture { /// Creates a capture for the given component. @@ -885,7 +874,7 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams)>( - @\(concatBuilderName) _ componentBuilder: () -> R + @\(concatBuilderName) _ componentBuilder: () -> some RegexComponent<\(matchType)> ) \(whereClauseRaw) { let factory = makeFactory() self.init(factory.capture(componentBuilder())) @@ -903,7 +892,7 @@ struct VariadicsGenerator: ParsableCommand { @_alwaysEmitIntoClient public init<\(genericParams)>( as reference: Reference, - @\(concatBuilderName) _ componentBuilder: () -> R + @\(concatBuilderName) _ componentBuilder: () -> some RegexComponent<\(matchType)> ) \(whereClauseRaw) { let factory = makeFactory() self.init(factory.capture(componentBuilder(), reference._raw)) @@ -922,7 +911,7 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( - @\(concatBuilderName) _ componentBuilder: () -> R, + @\(concatBuilderName) _ componentBuilder: () -> some RegexComponent<\(matchType)>, transform: @escaping (W) throws -> NewCapture ) \(whereClauseTransformed) { let factory = makeFactory() @@ -945,7 +934,7 @@ struct VariadicsGenerator: ParsableCommand { @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( as reference: Reference, - @\(concatBuilderName) _ componentBuilder: () -> R, + @\(concatBuilderName) _ componentBuilder: () -> some RegexComponent<\(matchType)>, transform: @escaping (W) throws -> NewCapture ) \(whereClauseTransformed) { let factory = makeFactory() @@ -969,7 +958,7 @@ struct VariadicsGenerator: ParsableCommand { \(disfavored)\ @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( - @\(concatBuilderName) _ componentBuilder: () -> R, + @\(concatBuilderName) _ componentBuilder: () -> some RegexComponent<\(matchType)>, transform: @escaping (W) throws -> NewCapture? ) \(whereClauseTransformed) { let factory = makeFactory() @@ -993,7 +982,7 @@ struct VariadicsGenerator: ParsableCommand { @_alwaysEmitIntoClient public init<\(genericParams), NewCapture>( as reference: Reference, - @\(concatBuilderName) _ componentBuilder: () -> R, + @\(concatBuilderName) _ componentBuilder: () -> some RegexComponent<\(matchType)>, transform: @escaping (W) throws -> NewCapture? ) \(whereClauseTransformed) { let factory = makeFactory() diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index 7d24e30af..115941070 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -120,17 +120,17 @@ class AlgorithmsResultBuilderTests: XCTestCase { case trimmingPrefix } - func expectMatch( + func expectMatch( _ algo: MatchAlgo, _ tests: (input: String, expectedCaptures: MatchType?)..., matchType: MatchType.Type, equivalence: (MatchType, MatchType) -> Bool, file: StaticString = #file, line: UInt = #line, - @RegexComponentBuilder _ content: () -> R + @RegexComponentBuilder _ content: () -> some RegexComponent ) throws { for (input, expectedCaptures) in tests { - var actual: Regex.Match? + var actual: Regex.Match? switch algo { case .whole: actual = input.wholeMatch(of: content) @@ -149,12 +149,12 @@ class AlgorithmsResultBuilderTests: XCTestCase { } } - func expectEqual( + func expectEqual( _ algo: EquatableAlgo, _ tests: (input: String, expected: Expected)..., file: StaticString = #file, line: UInt = #line, - @RegexComponentBuilder _ content: () -> R + @RegexComponentBuilder _ content: () -> some RegexComponent ) throws { for (input, expected) in tests { var actual: Expected diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index e560a80e3..0e529368a 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -16,15 +16,15 @@ import TestSupport @available(SwiftStdlib 5.7, *) class RegexDSLTests: XCTestCase { - func _testDSLCaptures( + func _testDSLCaptures( _ tests: (input: String, expectedCaptures: MatchType?)..., matchType: MatchType.Type, _ equivalence: (MatchType, MatchType) -> Bool, xfail: Bool = false, file: StaticString = #file, line: UInt = #line, - @RegexComponentBuilder _ content: () -> Content - ) throws where Content.RegexOutput == MatchType { + @RegexComponentBuilder _ content: () -> some RegexComponent + ) throws { let regex = content() for (input, maybeExpectedCaptures) in tests { let maybeMatch = input.wholeMatch(of: regex) diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index 8ff3ad607..d5419fe9c 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -98,10 +98,13 @@ class AlgorithmTests: XCTestCase { // `String.contains` get selected instead, which has inconsistent behavior. // Test that original `contains` functions are still accessible - let containsRef = "abcd".contains - XCTAssert(type(of: containsRef) == ((Character) -> Bool).self) - let containsParamsRef = "abcd".contains(_:) - XCTAssert(type(of: containsParamsRef) == ((Character) -> Bool).self) + + // rdar://105502403 + // Error: constructing SILType with type that should have been eliminated by SIL lowering + // let containsRef = "abcd".contains + // XCTAssert(type(of: containsRef) == ((Character) -> Bool).self) + // let containsParamsRef = "abcd".contains(_:) + // XCTAssert(type(of: containsParamsRef) == ((Character) -> Bool).self) } func testRegexRanges() { @@ -247,10 +250,13 @@ class AlgorithmTests: XCTestCase { XCTAssertEqual(CountedOptionSet.arrayLiteralCreationCount, 3) // Test that original `split` functions are still accessible - let splitRef = "abcd".split - XCTAssert(type(of: splitRef) == ((Character, Int, Bool) -> [Substring]).self) - let splitParamsRef = "abcd".split(separator:maxSplits:omittingEmptySubsequences:) - XCTAssert(type(of: splitParamsRef) == ((Character, Int, Bool) -> [Substring]).self) + + // rdar://105502403 + // Error: constructing SILType with type that should have been eliminated by SIL lowering + // let splitRef = "abcd".split + // XCTAssert(type(of: splitRef) == ((Character, Int, Bool) -> [Substring]).self) + // let splitParamsRef = "abcd".split(separator:maxSplits:omittingEmptySubsequences:) + // XCTAssert(type(of: splitParamsRef) == ((Character, Int, Bool) -> [Substring]).self) } func testSplitPermutations() throws { From 083d32a63b082491651da5b5ec20721624b70a69 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Sun, 2 Apr 2023 17:36:53 -0600 Subject: [PATCH 17/34] Type checker workaround: adjust test --- Tests/RegexBuilderTests/RegexDSLTests.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 0e529368a..b0a754fa5 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -1099,8 +1099,11 @@ class RegexDSLTests: XCTestCase { } let _: (Substring, Substring, Int, Double?).Type = type(of: regex3).RegexOutput.self - - let regex4 = Regex { + + // FIXME: Remove explicit type when type checker regression is fixed + let regex4: Regex<( + Substring, Substring, Substring, Substring, Substring? + )> = Regex { OneOrMore("a") Capture { OneOrMore { From ca92db7e5c4f0c68eb42d4adc46d86d0476449d9 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 3 Apr 2023 10:10:03 -0600 Subject: [PATCH 18/34] Further refactor to work around type checker regression --- Tests/RegexBuilderTests/RegexDSLTests.swift | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index b0a754fa5..5e85ad26c 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -1100,17 +1100,25 @@ class RegexDSLTests: XCTestCase { let _: (Substring, Substring, Int, Double?).Type = type(of: regex3).RegexOutput.self - // FIXME: Remove explicit type when type checker regression is fixed + // FIXME: Remove explicit type and `subregex1` and `subregex2` when type checker regression is fixed + let subregex1: Regex<(Substring, Substring?)> = Regex { + ZeroOrMore(Capture("d")) + } + let subregex2: Regex<( + Substring, Substring, Substring, Substring? + )> = Regex { + Capture(OneOrMore("b")) + Capture(ZeroOrMore("c")) + subregex1 + Optionally("e") + } let regex4: Regex<( Substring, Substring, Substring, Substring, Substring? )> = Regex { OneOrMore("a") Capture { OneOrMore { - Capture(OneOrMore("b")) - Capture(ZeroOrMore("c")) - ZeroOrMore(Capture("d")) - Optionally("e") + subregex2 } } } From 852b89035ca28b899bea765543c5d8fa786cc29f Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 3 Apr 2023 18:23:53 -0600 Subject: [PATCH 19/34] Align availability macro with OS versions (#641) --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 5d45950db..f02ef1828 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,7 @@ let availabilityDefinition = PackageDescription.SwiftSetting.unsafeFlags([ "-Xfrontend", "-define-availability", "-Xfrontend", - "SwiftStdlib 5.7:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999", + "SwiftStdlib 5.7:macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0", "-Xfrontend", "-define-availability", "-Xfrontend", From 236b47c5ded88a86f8aacbff4950c8114b64e860 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 3 Apr 2023 18:26:04 -0600 Subject: [PATCH 20/34] Speed up general character class matching (#642) Short-circuit Character.isASCII checks inside built in character class matching. Also, make benchmark try a few more times before giving up. --- Sources/RegexBenchmark/BenchmarkRunner.swift | 18 +++++++++++++----- .../_StringProcessing/Engine/MEBuiltins.swift | 4 ++-- .../_CharacterClassModel.swift | 5 +++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Sources/RegexBenchmark/BenchmarkRunner.swift b/Sources/RegexBenchmark/BenchmarkRunner.swift index 1a62858c1..641c03224 100644 --- a/Sources/RegexBenchmark/BenchmarkRunner.swift +++ b/Sources/RegexBenchmark/BenchmarkRunner.swift @@ -1,6 +1,9 @@ import Foundation @_spi(RegexBenchmark) import _StringProcessing +/// The number of times to re-run the benchmark if results are too varying +private var rerunCount: Int { 3 } + struct BenchmarkRunner { let suiteName: String var suite: [any RegexBenchmark] = [] @@ -82,11 +85,16 @@ struct BenchmarkRunner { for b in suite { var result = measure(benchmark: b, samples: samples) if result.runtimeIsTooVariant { - print("Warning: Standard deviation > \(Stats.maxAllowedStdev*100)% for \(b.name)") - print(result.runtime) - print("Rerunning \(b.name)") - result = measure(benchmark: b, samples: result.runtime.samples*2) - print(result.runtime) + for _ in 0.. \(Stats.maxAllowedStdev*100)% for \(b.name)") + print(result.runtime) + print("Rerunning \(b.name)") + result = measure(benchmark: b, samples: result.runtime.samples*2) + print(result.runtime) + if !result.runtimeIsTooVariant { + break + } + } if result.runtimeIsTooVariant { fatalError("Benchmark \(b.name) is too variant") } diff --git a/Sources/_StringProcessing/Engine/MEBuiltins.swift b/Sources/_StringProcessing/Engine/MEBuiltins.swift index 36a6043fe..6f99058fd 100644 --- a/Sources/_StringProcessing/Engine/MEBuiltins.swift +++ b/Sources/_StringProcessing/Engine/MEBuiltins.swift @@ -38,9 +38,9 @@ extension Processor { return nil } - let asciiCheck = (char.isASCII && !isScalarSemantics) + let asciiCheck = !isStrictASCII || (scalar.isASCII && isScalarSemantics) - || !isStrictASCII + || char.isASCII var matched: Bool var next: Input.Index diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index c5f1f8ecd..548a9eea0 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -81,9 +81,10 @@ struct _CharacterClassModel: Hashable { let char = input[currentPosition] let scalar = input.unicodeScalars[currentPosition] let isScalarSemantics = matchLevel == .unicodeScalar - let asciiCheck = (char.isASCII && !isScalarSemantics) + + let asciiCheck = !isStrictASCII || (scalar.isASCII && isScalarSemantics) - || !isStrictASCII + || char.isASCII var matched: Bool var next: String.Index From 348e6c3621110bae4a95d7e838ad228530d51c71 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Mon, 3 Apr 2023 19:26:35 -0500 Subject: [PATCH 21/34] Test for \s matching CRLF when scalar matching (#648) --- Tests/RegexTests/UTS18Tests.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Tests/RegexTests/UTS18Tests.swift b/Tests/RegexTests/UTS18Tests.swift index 4cf68a153..ae7aa2aa0 100644 --- a/Tests/RegexTests/UTS18Tests.swift +++ b/Tests/RegexTests/UTS18Tests.swift @@ -286,6 +286,9 @@ extension UTS18Tests { // Test \v - vertical space lines = lineInput.matches(of: regex(#"\d{2}\v^"#).anchorsMatchLineEndings()) XCTAssertEqual(lines.count, 11) + // Test \s - whitespace + lines = lineInput.matches(of: regex(#"\d{2}\s^"#).anchorsMatchLineEndings()) + XCTAssertEqual(lines.count, 11) // Test anchors as line boundaries lines = lineInput.matches(of: regex(#"^\d{2}$"#).anchorsMatchLineEndings()) XCTAssertEqual(lines.count, 12) @@ -301,6 +304,10 @@ extension UTS18Tests { lines = lineInput.matches( of: regex(#"\d{2}\v(?=\d)"#).matchingSemantics(.unicodeScalar).anchorsMatchLineEndings()) XCTAssertEqual(lines.count, 10) + // Unicode scalar semantics - \s matches all except for \r\n sequence + lines = lineInput.matches( + of: regex(#"\d{2}\s(?=\d)"#).matchingSemantics(.unicodeScalar).anchorsMatchLineEndings()) + XCTAssertEqual(lines.count, 10) // Does not contain an empty line XCTAssertFalse(lineInput.contains(regex(#"^$"#))) From a7ba70102eadf9854fd69de0ddec441e3b4ef122 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Tue, 4 Apr 2023 09:19:46 -0600 Subject: [PATCH 22/34] General ascii fast paths for character classes (#644) General ASCII fast-paths for builtin character classes --- Documentation/ProgrammersManual.md | 30 ++ Sources/_StringProcessing/CMakeLists.txt | 1 + .../_StringProcessing/Engine/MEBuiltins.swift | 259 +++++++++++------- .../_StringProcessing/Engine/MEQuantify.swift | 9 +- .../_StringProcessing/Engine/Processor.swift | 8 +- Sources/_StringProcessing/Unicode/ASCII.swift | 170 ++++++++++++ Sources/_StringProcessing/Unicode/NFC.swift | 5 + Sources/_StringProcessing/Utility/Misc.swift | 8 + .../_CharacterClassModel.swift | 89 +----- 9 files changed, 395 insertions(+), 184 deletions(-) create mode 100644 Documentation/ProgrammersManual.md create mode 100644 Sources/_StringProcessing/Unicode/ASCII.swift diff --git a/Documentation/ProgrammersManual.md b/Documentation/ProgrammersManual.md new file mode 100644 index 000000000..67021f44c --- /dev/null +++ b/Documentation/ProgrammersManual.md @@ -0,0 +1,30 @@ +# Programmer's Manual + +## Programming patterns + +### Engine quick checks and fast paths + +In the engine nomenclature, a quick-check results in a yes/no/maybe while a thorough check always results in a definite answer. + +The nature of quick checks and fast paths is that they bifurcate testing coverage. One easy way to prevent this in simple cases is to assert that a definite quick result matches the thorough result. + +One example of this pattern is matching against a builtin character class. The engine has a `_matchBuiltinCC` + +```swift + func _matchBuiltinCC(...) -> Input.Index? { + // Calls _quickMatchBuiltinCC, if that gives a definite result + // asserts that it is the same as the result of + // _thoroughMatchBuiltinCC and returns it. Otherwise returns the + // result of _thoroughMatchBuiltinCC + } + + @inline(__always) + func _quickMatchBuiltinCC(...) -> QuickResult + + @inline(never) + func _thoroughMatchBuiltinCC(...) -> Input.Index? +``` + +The thorough check is never inlined, as it is a lot of cold code. Note that quick and thorough functions should be pure, that is they shouldn't update processor state. + + diff --git a/Sources/_StringProcessing/CMakeLists.txt b/Sources/_StringProcessing/CMakeLists.txt index ba3e2e03c..ef4aeb6ef 100644 --- a/Sources/_StringProcessing/CMakeLists.txt +++ b/Sources/_StringProcessing/CMakeLists.txt @@ -47,6 +47,7 @@ add_library(_StringProcessing Regex/DSLTree.swift Regex/Match.swift Regex/Options.swift + Unicode/ASCII.swift Unicode/CaseConversion.swift Unicode/CharacterProps.swift Unicode/Comparison.swift diff --git a/Sources/_StringProcessing/Engine/MEBuiltins.swift b/Sources/_StringProcessing/Engine/MEBuiltins.swift index 6f99058fd..fa4f8fa1a 100644 --- a/Sources/_StringProcessing/Engine/MEBuiltins.swift +++ b/Sources/_StringProcessing/Engine/MEBuiltins.swift @@ -9,17 +9,18 @@ extension Character { } extension Processor { - mutating func matchBuiltin( + mutating func matchBuiltinCC( _ cc: _CharacterClassModel.Representation, - _ isInverted: Bool, - _ isStrictASCII: Bool, - _ isScalarSemantics: Bool + isInverted: Bool, + isStrictASCII: Bool, + isScalarSemantics: Bool ) -> Bool { - guard let next = _doMatchBuiltin( + guard let next = input._matchBuiltinCC( cc, - isInverted, - isStrictASCII, - isScalarSemantics + at: currentPosition, + isInverted: isInverted, + isStrictASCII: isStrictASCII, + isScalarSemantics: isScalarSemantics ) else { signalFailure() return false @@ -27,96 +28,7 @@ extension Processor { currentPosition = next return true } - - func _doMatchBuiltin( - _ cc: _CharacterClassModel.Representation, - _ isInverted: Bool, - _ isStrictASCII: Bool, - _ isScalarSemantics: Bool - ) -> Input.Index? { - guard let char = load(), let scalar = loadScalar() else { - return nil - } - - let asciiCheck = !isStrictASCII - || (scalar.isASCII && isScalarSemantics) - || char.isASCII - - var matched: Bool - var next: Input.Index - switch (isScalarSemantics, cc) { - case (_, .anyGrapheme): - next = input.index(after: currentPosition) - case (_, .anyScalar): - next = input.unicodeScalars.index(after: currentPosition) - case (true, _): - next = input.unicodeScalars.index(after: currentPosition) - case (false, _): - next = input.index(after: currentPosition) - } - - switch cc { - case .any, .anyGrapheme: - matched = true - case .anyScalar: - if isScalarSemantics { - matched = true - } else { - matched = input.isOnGraphemeClusterBoundary(next) - } - case .digit: - if isScalarSemantics { - matched = scalar.properties.numericType != nil && asciiCheck - } else { - matched = char.isNumber && asciiCheck - } - case .horizontalWhitespace: - if isScalarSemantics { - matched = scalar.isHorizontalWhitespace && asciiCheck - } else { - matched = char._isHorizontalWhitespace && asciiCheck - } - case .verticalWhitespace: - if isScalarSemantics { - matched = scalar.isNewline && asciiCheck - } else { - matched = char._isNewline && asciiCheck - } - case .newlineSequence: - if isScalarSemantics { - matched = scalar.isNewline && asciiCheck - if matched && scalar == "\r" - && next != input.endIndex && input.unicodeScalars[next] == "\n" { - // Match a full CR-LF sequence even in scalar semantics - input.unicodeScalars.formIndex(after: &next) - } - } else { - matched = char._isNewline && asciiCheck - } - case .whitespace: - if isScalarSemantics { - matched = scalar.properties.isWhitespace && asciiCheck - } else { - matched = char.isWhitespace && asciiCheck - } - case .word: - if isScalarSemantics { - matched = scalar.properties.isAlphabetic && asciiCheck - } else { - matched = char.isWordCharacter && asciiCheck - } - } - - if isInverted { - matched.toggle() - } - guard matched else { - return nil - } - return next - } - func isAtStartOfLine(_ payload: AssertionPayload) -> Bool { if currentPosition == subjectBounds.lowerBound { return true } switch payload.semanticLevel { @@ -126,7 +38,7 @@ extension Processor { return input.unicodeScalars[input.unicodeScalars.index(before: currentPosition)].isNewline } } - + func isAtEndOfLine(_ payload: AssertionPayload) -> Bool { if currentPosition == subjectBounds.upperBound { return true } switch payload.semanticLevel { @@ -169,7 +81,7 @@ extension Processor { return isAtStartOfLine(payload) case .endOfLine: return isAtEndOfLine(payload) - + case .caretAnchor: if payload.anchorsMatchNewlines { return isAtStartOfLine(payload) @@ -202,3 +114,152 @@ extension Processor { } } } + +// MARK: Built-in character class matching + +extension String { + + // Mentioned in ProgrammersManual.md, update docs if redesigned + func _matchBuiltinCC( + _ cc: _CharacterClassModel.Representation, + at currentPosition: String.Index, + isInverted: Bool, + isStrictASCII: Bool, + isScalarSemantics: Bool + ) -> String.Index? { + guard currentPosition < endIndex else { + return nil + } + if case .definite(let result) = _quickMatchBuiltinCC( + cc, + at: currentPosition, + isInverted: isInverted, + isStrictASCII: isStrictASCII, + isScalarSemantics: isScalarSemantics + ) { + assert(result == _thoroughMatchBuiltinCC( + cc, + at: currentPosition, + isInverted: isInverted, + isStrictASCII: isStrictASCII, + isScalarSemantics: isScalarSemantics)) + return result + } + return _thoroughMatchBuiltinCC( + cc, + at: currentPosition, + isInverted: isInverted, + isStrictASCII: isStrictASCII, + isScalarSemantics: isScalarSemantics) + } + + // Mentioned in ProgrammersManual.md, update docs if redesigned + @inline(__always) + func _quickMatchBuiltinCC( + _ cc: _CharacterClassModel.Representation, + at currentPosition: String.Index, + isInverted: Bool, + isStrictASCII: Bool, + isScalarSemantics: Bool + ) -> QuickResult { + assert(currentPosition < endIndex) + guard let (next, result) = _quickMatch( + cc, at: currentPosition, isScalarSemantics: isScalarSemantics + ) else { + return .unknown + } + return .definite(result == isInverted ? nil : next) + } + + // Mentioned in ProgrammersManual.md, update docs if redesigned + @inline(never) + func _thoroughMatchBuiltinCC( + _ cc: _CharacterClassModel.Representation, + at currentPosition: String.Index, + isInverted: Bool, + isStrictASCII: Bool, + isScalarSemantics: Bool + ) -> String.Index? { + assert(currentPosition < endIndex) + let char = self[currentPosition] + let scalar = unicodeScalars[currentPosition] + + let asciiCheck = !isStrictASCII + || (scalar.isASCII && isScalarSemantics) + || char.isASCII + + var matched: Bool + var next: String.Index + switch (isScalarSemantics, cc) { + case (_, .anyGrapheme): + next = index(after: currentPosition) + case (_, .anyScalar): + next = unicodeScalars.index(after: currentPosition) + case (true, _): + next = unicodeScalars.index(after: currentPosition) + case (false, _): + next = index(after: currentPosition) + } + + switch cc { + case .any, .anyGrapheme: + matched = true + case .anyScalar: + if isScalarSemantics { + matched = true + } else { + matched = isOnGraphemeClusterBoundary(next) + } + case .digit: + if isScalarSemantics { + matched = scalar.properties.numericType != nil && asciiCheck + } else { + matched = char.isNumber && asciiCheck + } + case .horizontalWhitespace: + if isScalarSemantics { + matched = scalar.isHorizontalWhitespace && asciiCheck + } else { + matched = char._isHorizontalWhitespace && asciiCheck + } + case .verticalWhitespace: + if isScalarSemantics { + matched = scalar.isNewline && asciiCheck + } else { + matched = char._isNewline && asciiCheck + } + case .newlineSequence: + if isScalarSemantics { + matched = scalar.isNewline && asciiCheck + if matched && scalar == "\r" + && next != endIndex && unicodeScalars[next] == "\n" { + // Match a full CR-LF sequence even in scalar semantics + unicodeScalars.formIndex(after: &next) + } + } else { + matched = char._isNewline && asciiCheck + } + case .whitespace: + if isScalarSemantics { + matched = scalar.properties.isWhitespace && asciiCheck + } else { + matched = char.isWhitespace && asciiCheck + } + case .word: + if isScalarSemantics { + matched = scalar.properties.isAlphabetic && asciiCheck + } else { + matched = char.isWordCharacter && asciiCheck + } + } + + if isInverted { + matched.toggle() + } + + guard matched else { + return nil + } + return next + } +} diff --git a/Sources/_StringProcessing/Engine/MEQuantify.swift b/Sources/_StringProcessing/Engine/MEQuantify.swift index 9d17dc9bd..fa68b8b76 100644 --- a/Sources/_StringProcessing/Engine/MEQuantify.swift +++ b/Sources/_StringProcessing/Engine/MEQuantify.swift @@ -9,11 +9,12 @@ extension Processor { UnicodeScalar.init(_value: UInt32(payload.asciiChar)), true) case .builtin: // We only emit .quantify if it consumes a single character - next = _doMatchBuiltin( + next = input._matchBuiltinCC( payload.builtin, - payload.builtinIsInverted, - payload.builtinIsStrict, - false) + at: currentPosition, + isInverted: payload.builtinIsInverted, + isStrictASCII: payload.builtinIsStrict, + isScalarSemantics: false) case .any: let matched = currentPosition != input.endIndex && (!input[currentPosition].isNewline || payload.anyMatchesNewline) diff --git a/Sources/_StringProcessing/Engine/Processor.swift b/Sources/_StringProcessing/Engine/Processor.swift index 18e355fb5..25cad5c8c 100644 --- a/Sources/_StringProcessing/Engine/Processor.swift +++ b/Sources/_StringProcessing/Engine/Processor.swift @@ -583,11 +583,11 @@ extension Processor { case .matchBuiltin: let payload = payload.characterClassPayload - if matchBuiltin( + if matchBuiltinCC( payload.cc, - payload.isInverted, - payload.isStrictASCII, - payload.isScalarSemantics + isInverted: payload.isInverted, + isStrictASCII: payload.isStrictASCII, + isScalarSemantics: payload.isScalarSemantics ) { controller.step() } diff --git a/Sources/_StringProcessing/Unicode/ASCII.swift b/Sources/_StringProcessing/Unicode/ASCII.swift new file mode 100644 index 000000000..f27584893 --- /dev/null +++ b/Sources/_StringProcessing/Unicode/ASCII.swift @@ -0,0 +1,170 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021-2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +private var _lineFeed: UInt8 { 0x0A } +private var _carriageReturn: UInt8 { 0x0D } +private var _lineTab: UInt8 { 0x0B } +private var _formFeed: UInt8 { 0x0C } +private var _space: UInt8 { 0x20 } +private var _tab: UInt8 { 0x09 } + +private var _0: UInt8 { 0x30 } +private var _9: UInt8 { 0x39 } +private func _isASCIINumber(_ x: UInt8) -> Bool { + return (_0..._9).contains(x) +} + +private var _a: UInt8 { 0x61 } +private var _z: UInt8 { 0x7A } +private var _A: UInt8 { 0x41 } +private var _Z: UInt8 { 0x5A } + +private var _underscore: UInt8 { 0x5F } + +extension UInt8 { + var _isASCII: Bool { self < 0x80 } + + // TODO: Bitvectors for the below + + /// Assuming we're ASCII, whether we match `\d` + var _asciiIsDigit: Bool { + assert(_isASCII) + return(_0..._9).contains(self) + } + + /// Assuming we're ASCII, whether we match `\h` + var _asciiIsHorizontalWhitespace: Bool { + assert(_isASCII) + return self == _space || self == _tab + } + + /// Assuming we're ASCII, whether we match `\v` + var _asciiIsVerticalWhitespace: Bool { + assert(_isASCII) + switch self { + case _lineFeed, _carriageReturn, _lineTab, _formFeed: + return true + default: + return false + } + } + + /// Assuming we're ASCII, whether we match `\s` + var _asciiIsWhitespace: Bool { + assert(_isASCII) + switch self { + case _space, _tab, _lineFeed, _lineTab, _formFeed, _carriageReturn: + return true + default: + return false + } + } + + /// Assuming we're ASCII, whether we match `[a-zA-Z]` + var _asciiIsLetter: Bool { + assert(_isASCII) + return (_a..._z).contains(self) || (_A..._Z).contains(self) + } + + /// Assuming we're ASCII, whether we match `\w` + var _asciiIsWord: Bool { + assert(_isASCII) + return _asciiIsDigit || _asciiIsLetter || self == _underscore + } +} + +extension String { + /// TODO: detailed description of nuanced semantics + func _quickASCIICharacter( + at idx: Index + ) -> (first: UInt8, next: Index, crLF: Bool)? { + // TODO: fastUTF8 version + + if idx == endIndex { + return nil + } + let base = utf8[idx] + guard base._isASCII else { + assert(!self[idx].isASCII) + return nil + } + + var next = utf8.index(after: idx) + if next == utf8.endIndex { + assert(self[idx].isASCII) + return (first: base, next: next, crLF: false) + } + + let tail = utf8[next] + guard tail._isSub300StartingByte else { return nil } + + // Handle CR-LF: + if base == _carriageReturn && tail == _lineFeed { + utf8.formIndex(after: &next) + guard next == endIndex || utf8[next]._isSub300StartingByte else { + return nil + } + assert(self[idx] == "\r\n") + return (first: base, next: next, crLF: true) + } + + assert(self[idx].isASCII && self[idx] != "\r\n") + return (first: base, next: next, crLF: false) + } + + func _quickMatch( + _ cc: _CharacterClassModel.Representation, + at idx: Index, + isScalarSemantics: Bool + ) -> (next: Index, matchResult: Bool)? { + /// ASCII fast-paths + guard let (asciiValue, next, isCRLF) = _quickASCIICharacter( + at: idx + ) else { + return nil + } + + // TODO: bitvectors + switch cc { + case .any, .anyGrapheme, .anyScalar: + // TODO: should any scalar not consume CR-LF in scalar semantic mode? + return (next, true) + + case .digit: + return (next, asciiValue._asciiIsDigit) + + case .horizontalWhitespace: + return (next, asciiValue._asciiIsHorizontalWhitespace) + + case .verticalWhitespace, .newlineSequence: + if asciiValue._asciiIsVerticalWhitespace { + if isScalarSemantics && isCRLF && cc == .verticalWhitespace { + return (utf8.index(before: next), true) + } + return (next, true) + } + return (next, false) + + case .whitespace: + if asciiValue._asciiIsWhitespace { + if isScalarSemantics && isCRLF { + return (utf8.index(before: next), true) + } + return (next, true) + } + return (next, false) + + case .word: + return (next, asciiValue._asciiIsWord) + } + } +} + diff --git a/Sources/_StringProcessing/Unicode/NFC.swift b/Sources/_StringProcessing/Unicode/NFC.swift index 5c2c4aa48..59d195bb6 100644 --- a/Sources/_StringProcessing/Unicode/NFC.swift +++ b/Sources/_StringProcessing/Unicode/NFC.swift @@ -12,6 +12,11 @@ @_spi(_Unicode) import Swift +extension UInt8 { + /// Whether this is the starting byte of a sub-300 (i.e. pre-combining scalar) scalars + var _isSub300StartingByte: Bool { self < 0xCC } +} + extension UnicodeScalar { /// Checks whether the scalar is in NFC form. var isNFC: Bool { Character(self).singleNFCScalar == self } diff --git a/Sources/_StringProcessing/Utility/Misc.swift b/Sources/_StringProcessing/Utility/Misc.swift index 8a9cbe325..8555ec85c 100644 --- a/Sources/_StringProcessing/Utility/Misc.swift +++ b/Sources/_StringProcessing/Utility/Misc.swift @@ -57,3 +57,11 @@ extension Array { with: initialAccumulator, into: { [finish($0) ]}, accumulate: accumulate) } } + +/// An enum for quick-check functions, which could return an answer or indefinite. +/// We use a separate type because often the answer itself is optional. +enum QuickResult { + case definite(_ r: R) + case unknown +} + diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index 548a9eea0..35a11a7ef 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -18,10 +18,10 @@ struct _CharacterClassModel: Hashable { /// The actual character class to match. let cc: Representation - + /// The level (character or Unicode scalar) at which to match. let matchLevel: MatchingOptions.SemanticLevel - + /// If this character character class only matches ascii characters let isStrictASCII: Bool @@ -61,7 +61,7 @@ struct _CharacterClassModel: Hashable { /// Character.isLetter or Character.isDigit or Character == "_" case word } - + /// Returns the end of the match of this character class in the string. /// /// - Parameter str: The string to match against. @@ -78,82 +78,15 @@ struct _CharacterClassModel: Hashable { guard currentPosition != input.endIndex else { return nil } - let char = input[currentPosition] - let scalar = input.unicodeScalars[currentPosition] - let isScalarSemantics = matchLevel == .unicodeScalar - let asciiCheck = !isStrictASCII - || (scalar.isASCII && isScalarSemantics) - || char.isASCII - - var matched: Bool - var next: String.Index - switch (isScalarSemantics, cc) { - case (_, .anyGrapheme): - next = input.index(after: currentPosition) - case (_, .anyScalar): - // FIXME: This allows us to be not-scalar aligned when in grapheme mode - // Should this even be allowed? - next = input.unicodeScalars.index(after: currentPosition) - case (true, _): - next = input.unicodeScalars.index(after: currentPosition) - case (false, _): - next = input.index(after: currentPosition) - } + let isScalarSemantics = matchLevel == .unicodeScalar - switch cc { - case .any, .anyGrapheme, .anyScalar: - matched = true - case .digit: - if isScalarSemantics { - matched = scalar.properties.numericType != nil && asciiCheck - } else { - matched = char.isNumber && asciiCheck - } - case .horizontalWhitespace: - if isScalarSemantics { - matched = scalar.isHorizontalWhitespace && asciiCheck - } else { - matched = char._isHorizontalWhitespace && asciiCheck - } - case .verticalWhitespace: - if isScalarSemantics { - matched = scalar.isNewline && asciiCheck - } else { - matched = char._isNewline && asciiCheck - } - case .newlineSequence: - if isScalarSemantics { - matched = scalar.isNewline && asciiCheck - if matched && scalar == "\r" - && next != input.endIndex && input.unicodeScalars[next] == "\n" { - // Match a full CR-LF sequence even in scalar sematnics - input.unicodeScalars.formIndex(after: &next) - } - } else { - matched = char._isNewline && asciiCheck - } - case .whitespace: - if isScalarSemantics { - matched = scalar.properties.isWhitespace && asciiCheck - } else { - matched = char.isWhitespace && asciiCheck - } - case .word: - if isScalarSemantics { - matched = scalar.properties.isAlphabetic && asciiCheck - } else { - matched = char.isWordCharacter && asciiCheck - } - } - if isInverted { - matched.toggle() - } - if matched { - return next - } else { - return nil - } + return input._matchBuiltinCC( + cc, + at: currentPosition, + isInverted: isInverted, + isStrictASCII: isStrictASCII, + isScalarSemantics: isScalarSemantics) } } @@ -257,3 +190,5 @@ extension DSLTree.Atom.CharacterClass { return _CharacterClassModel(cc: cc, options: options, isInverted: inverted) } } + + From e01e43d3f753cee6e25fbaadc26b0d624e5c6ad9 Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 4 Apr 2023 16:35:40 -0500 Subject: [PATCH 23/34] Remove the unsupported `anyScalar` case (#650) We decided not to support the `anyScalar` character class, which would match a single Unicode scalar regardless of matching mode. However, its representation was still included in the various character class types in the regex engine, leading to unreachable code and unclear requirements when changing or adding new code. This change removes that representation where possible. The `DSLTree.Atom.CharacterClass` enum is left unchanged, since it is marked `@_spi(RegexBuilder) public`. Any use of that enum case is handled with a `fatalError("Unsupported")`, and it isn't produced on any code path. --- Sources/_StringProcessing/ByteCodeGen.swift | 3 --- Sources/_StringProcessing/Engine/MEBuiltins.swift | 8 -------- Sources/_StringProcessing/PrintAsPattern.swift | 4 ++-- .../_StringProcessing/Regex/ASTConversion.swift | 1 - Sources/_StringProcessing/Regex/DSLTree.swift | 3 ++- Sources/_StringProcessing/Unicode/ASCII.swift | 3 +-- .../_StringProcessing/_CharacterClassModel.swift | 14 +------------- 7 files changed, 6 insertions(+), 30 deletions(-) diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index 15e052901..d4c91bd63 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -702,9 +702,6 @@ fileprivate extension Compiler.ByteCodeGen { case .characterClass(let cc): // Custom character class that consumes a single grapheme let model = cc.asRuntimeModel(options) - guard model.consumesSingleGrapheme else { - return false - } builder.buildQuantify( model: model, kind, diff --git a/Sources/_StringProcessing/Engine/MEBuiltins.swift b/Sources/_StringProcessing/Engine/MEBuiltins.swift index fa4f8fa1a..a3d864165 100644 --- a/Sources/_StringProcessing/Engine/MEBuiltins.swift +++ b/Sources/_StringProcessing/Engine/MEBuiltins.swift @@ -193,8 +193,6 @@ extension String { switch (isScalarSemantics, cc) { case (_, .anyGrapheme): next = index(after: currentPosition) - case (_, .anyScalar): - next = unicodeScalars.index(after: currentPosition) case (true, _): next = unicodeScalars.index(after: currentPosition) case (false, _): @@ -204,12 +202,6 @@ extension String { switch cc { case .any, .anyGrapheme: matched = true - case .anyScalar: - if isScalarSemantics { - matched = true - } else { - matched = isOnGraphemeClusterBoundary(next) - } case .digit: if isScalarSemantics { matched = scalar.properties.numericType != nil && asciiCheck diff --git a/Sources/_StringProcessing/PrintAsPattern.swift b/Sources/_StringProcessing/PrintAsPattern.swift index 3d2d38842..08c40157a 100644 --- a/Sources/_StringProcessing/PrintAsPattern.swift +++ b/Sources/_StringProcessing/PrintAsPattern.swift @@ -760,8 +760,6 @@ extension DSLTree.Atom.CharacterClass { switch self { case .anyGrapheme: return ".anyGraphemeCluster" - case .anyUnicodeScalar: - return ".anyUnicodeScalar" case .digit: return ".digit" case .notDigit: @@ -786,6 +784,8 @@ extension DSLTree.Atom.CharacterClass { return ".whitespace" case .notWhitespace: return ".whitespace.inverted" + case .anyUnicodeScalar: + fatalError("Unsupported") } } } diff --git a/Sources/_StringProcessing/Regex/ASTConversion.swift b/Sources/_StringProcessing/Regex/ASTConversion.swift index f5b08dd6d..6af0924cb 100644 --- a/Sources/_StringProcessing/Regex/ASTConversion.swift +++ b/Sources/_StringProcessing/Regex/ASTConversion.swift @@ -183,7 +183,6 @@ extension AST.Atom.EscapedBuiltin { case .wordCharacter: return .word case .notWordCharacter: return .notWord case .graphemeCluster: return .anyGrapheme - case .trueAnychar: return .anyUnicodeScalar default: return nil } } diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index 93e86c607..b784e2382 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -260,7 +260,6 @@ extension DSLTree.Atom.CharacterClass { public var inverted: DSLTree.Atom.CharacterClass? { switch self { case .anyGrapheme: return nil - case .anyUnicodeScalar: return nil case .digit: return .notDigit case .notDigit: return .digit case .word: return .notWord @@ -273,6 +272,8 @@ extension DSLTree.Atom.CharacterClass { case .notVerticalWhitespace: return .verticalWhitespace case .whitespace: return .notWhitespace case .notWhitespace: return .whitespace + case .anyUnicodeScalar: + fatalError("Unsupported") } } } diff --git a/Sources/_StringProcessing/Unicode/ASCII.swift b/Sources/_StringProcessing/Unicode/ASCII.swift index f27584893..5150e18cc 100644 --- a/Sources/_StringProcessing/Unicode/ASCII.swift +++ b/Sources/_StringProcessing/Unicode/ASCII.swift @@ -134,8 +134,7 @@ extension String { // TODO: bitvectors switch cc { - case .any, .anyGrapheme, .anyScalar: - // TODO: should any scalar not consume CR-LF in scalar semantic mode? + case .any, .anyGrapheme: return (next, true) case .digit: diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index 35a11a7ef..cdee66ddb 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -45,8 +45,6 @@ struct _CharacterClassModel: Hashable { case any = 0 /// Any grapheme cluster case anyGrapheme - /// Any Unicode scalar - case anyScalar /// Character.isDigit case digit /// Horizontal whitespace: `[:blank:]`, i.e @@ -90,15 +88,6 @@ struct _CharacterClassModel: Hashable { } } -extension _CharacterClassModel { - var consumesSingleGrapheme: Bool { - switch self.cc { - case .anyScalar: return false - default: return true - } - } -} - extension _CharacterClassModel.Representation { /// Returns true if this CharacterClass should be matched by strict ascii under the given options func isStrictAscii(options: MatchingOptions) -> Bool { @@ -119,7 +108,6 @@ extension _CharacterClassModel.Representation: CustomStringConvertible { switch self { case .any: return "" case .anyGrapheme: return "" - case .anyScalar: return "" case .digit: return "" case .horizontalWhitespace: return "" case .newlineSequence: return "" @@ -185,7 +173,7 @@ extension DSLTree.Atom.CharacterClass { case .anyGrapheme: cc = .anyGrapheme case .anyUnicodeScalar: - cc = .anyScalar + fatalError("Unsupported") } return _CharacterClassModel(cc: cc, options: options, isInverted: inverted) } From e0352a2663410340edc50bccc3cfdf2dcec5a0fd Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 11 Apr 2023 12:06:34 -0500 Subject: [PATCH 24/34] Fix range-based quantification fast path (#653) The fast path for quantification incorrectly discards the last save position when the quantification used up all possible trips, which is only possible with range-based quantifications (e.g. `{0,3}`). This bug shows up when a range-based quantifier matches the maximum - 1 repetitions of the preceding pattern. For example, the regex `/a{0,2}a/` should succeed as a full match any of the strings "aa", "aaa", or "aaaa". However, the pattern fails to match "aaa", since the save point allowing a single "a" to match the first `a{0,2}` part of the regex is discarded. This change only discards the last save position when advancing the quantifier fails due to a failure to match, not maxing out the number of trips. --- .../_StringProcessing/Engine/MEQuantify.swift | 17 +++++----- Tests/RegexTests/MatchTests.swift | 31 +++++++++++++++++++ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/Sources/_StringProcessing/Engine/MEQuantify.swift b/Sources/_StringProcessing/Engine/MEQuantify.swift index fa68b8b76..0e2f3923a 100644 --- a/Sources/_StringProcessing/Engine/MEQuantify.swift +++ b/Sources/_StringProcessing/Engine/MEQuantify.swift @@ -40,7 +40,14 @@ extension Processor { } } let next = _doQuantifyMatch(payload) - guard let idx = next else { break } + guard let idx = next else { + if !savePoint.rangeIsEmpty { + // The last save point has saved the current, non-matching position, + // so it's unneeded. + savePoint.shrinkRange(input) + } + break + } currentPosition = idx trips += 1 } @@ -50,12 +57,8 @@ extension Processor { return false } - if payload.quantKind == .eager && !savePoint.rangeIsEmpty { - // The last save point has saved the current position, so it's unneeded - savePoint.shrinkRange(input) - if !savePoint.rangeIsEmpty { - savePoints.append(savePoint) - } + if !savePoint.rangeIsEmpty { + savePoints.append(savePoint) } return true } diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index a1bf0e76f..e8e41a114 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -2574,4 +2574,35 @@ extension RegexTests { func testFuzzerArtifacts() throws { expectCompletion(regex: #"(b?)\1*"#, in: "a") } + + func testIssue640() throws { + // Original report from https://github.com/apple/swift-experimental-string-processing/issues/640 + let original = try Regex("[1-9][0-9]{0,2}(?:,?[0-9]{3})*") + XCTAssertNotNil("36,769".wholeMatch(of: original)) + XCTAssertNotNil("36769".wholeMatch(of: original)) + + // Simplified case + let simplified = try Regex("a{0,2}a") + XCTAssertNotNil("aaa".wholeMatch(of: simplified)) + + for max in 1...8 { + let patternEager = "a{0,\(max)}a" + let regexEager = try Regex(patternEager) + let patternReluctant = "a{0,\(max)}?a" + let regexReluctant = try Regex(patternReluctant) + for length in 1...(max + 1) { + let str = String(repeating: "a", count: length) + if str.wholeMatch(of: regexEager) == nil { + XCTFail("Didn't match '\(patternEager)' in '\(str)' (\(max),\(length)).") + } + if str.wholeMatch(of: regexReluctant) == nil { + XCTFail("Didn't match '\(patternReluctant)' in '\(str)' (\(max),\(length)).") + } + } + + let possessiveRegex = try Regex("a{0,\(max)}+a") + let str = String(repeating: "a", count: max + 1) + XCTAssertNotNil(str.wholeMatch(of: possessiveRegex)) + } + } } From 923cf5e2beaa68e7c5197442f5cfc4b0a737c256 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Tue, 11 Apr 2023 12:28:34 -0600 Subject: [PATCH 25/34] Add in ASCII fast-path for anyNonNewline (#654) --- .../_StringProcessing/Engine/MEBuiltins.swift | 63 ++++++++++++++++++- .../_StringProcessing/Engine/Processor.swift | 33 ++++------ Sources/_StringProcessing/Unicode/ASCII.swift | 34 +++++----- 3 files changed, 91 insertions(+), 39 deletions(-) diff --git a/Sources/_StringProcessing/Engine/MEBuiltins.swift b/Sources/_StringProcessing/Engine/MEBuiltins.swift index a3d864165..4ec7a71dd 100644 --- a/Sources/_StringProcessing/Engine/MEBuiltins.swift +++ b/Sources/_StringProcessing/Engine/MEBuiltins.swift @@ -115,8 +115,69 @@ extension Processor { } } -// MARK: Built-in character class matching +// MARK: Matching `.` +extension String { + + func _matchAnyNonNewline( + at currentPosition: String.Index, + isScalarSemantics: Bool + ) -> String.Index? { + guard currentPosition < endIndex else { + return nil + } + if case .definite(let result) = _quickMatchAnyNonNewline( + at: currentPosition, + isScalarSemantics: isScalarSemantics + ) { + assert(result == _thoroughMatchAnyNonNewline( + at: currentPosition, + isScalarSemantics: isScalarSemantics)) + return result + } + return _thoroughMatchAnyNonNewline( + at: currentPosition, + isScalarSemantics: isScalarSemantics) + } + + @inline(__always) + func _quickMatchAnyNonNewline( + at currentPosition: String.Index, + isScalarSemantics: Bool + ) -> QuickResult { + assert(currentPosition < endIndex) + guard let (asciiValue, next, isCRLF) = _quickASCIICharacter( + at: currentPosition + ) else { + return .unknown + } + switch asciiValue { + case ._lineFeed, ._carriageReturn: + return .definite(nil) + default: + assert(!isCRLF) + return .definite(next) + } + } + + @inline(never) + func _thoroughMatchAnyNonNewline( + at currentPosition: String.Index, + isScalarSemantics: Bool + ) -> String.Index? { + assert(currentPosition < endIndex) + if isScalarSemantics { + let scalar = unicodeScalars[currentPosition] + guard !scalar.isNewline else { return nil } + return unicodeScalars.index(after: currentPosition) + } + + let char = self[currentPosition] + guard !char.isNewline else { return nil } + return index(after: currentPosition) + } +} +// MARK: - Built-in character class matching extension String { // Mentioned in ProgrammersManual.md, update docs if redesigned diff --git a/Sources/_StringProcessing/Engine/Processor.swift b/Sources/_StringProcessing/Engine/Processor.swift index 25cad5c8c..98aee7803 100644 --- a/Sources/_StringProcessing/Engine/Processor.swift +++ b/Sources/_StringProcessing/Engine/Processor.swift @@ -346,23 +346,18 @@ extension Processor { return true } - // Matches the next character if it is not a newline - mutating func matchAnyNonNewline() -> Bool { - guard let c = load(), !c.isNewline else { - signalFailure() - return false - } - _uncheckedForcedConsumeOne() - return true - } - - // Matches the next scalar if it is not a newline - mutating func matchAnyNonNewlineScalar() -> Bool { - guard let s = loadScalar(), !s.isNewline else { + // Matches the next character/scalar if it is not a newline + mutating func matchAnyNonNewline( + isScalarSemantics: Bool + ) -> Bool { + guard let next = input._matchAnyNonNewline( + at: currentPosition, + isScalarSemantics: isScalarSemantics + ) else { signalFailure() return false } - input.unicodeScalars.formIndex(after: ¤tPosition) + currentPosition = next return true } @@ -535,14 +530,8 @@ extension Processor { } } case .matchAnyNonNewline: - if payload.isScalar { - if matchAnyNonNewlineScalar() { - controller.step() - } - } else { - if matchAnyNonNewline() { - controller.step() - } + if matchAnyNonNewline(isScalarSemantics: payload.isScalar) { + controller.step() } case .match: let (isCaseInsensitive, reg) = payload.elementPayload diff --git a/Sources/_StringProcessing/Unicode/ASCII.swift b/Sources/_StringProcessing/Unicode/ASCII.swift index 5150e18cc..de13e340a 100644 --- a/Sources/_StringProcessing/Unicode/ASCII.swift +++ b/Sources/_StringProcessing/Unicode/ASCII.swift @@ -9,26 +9,25 @@ // //===----------------------------------------------------------------------===// -private var _lineFeed: UInt8 { 0x0A } -private var _carriageReturn: UInt8 { 0x0D } -private var _lineTab: UInt8 { 0x0B } -private var _formFeed: UInt8 { 0x0C } -private var _space: UInt8 { 0x20 } -private var _tab: UInt8 { 0x09 } +extension UInt8 { + static var _lineFeed: UInt8 { 0x0A } + static var _carriageReturn: UInt8 { 0x0D } + static var _lineTab: UInt8 { 0x0B } + static var _formFeed: UInt8 { 0x0C } + static var _space: UInt8 { 0x20 } + static var _tab: UInt8 { 0x09 } + + static var _underscore: UInt8 { 0x5F } +} private var _0: UInt8 { 0x30 } private var _9: UInt8 { 0x39 } -private func _isASCIINumber(_ x: UInt8) -> Bool { - return (_0..._9).contains(x) -} private var _a: UInt8 { 0x61 } private var _z: UInt8 { 0x7A } private var _A: UInt8 { 0x41 } private var _Z: UInt8 { 0x5A } -private var _underscore: UInt8 { 0x5F } - extension UInt8 { var _isASCII: Bool { self < 0x80 } @@ -43,14 +42,14 @@ extension UInt8 { /// Assuming we're ASCII, whether we match `\h` var _asciiIsHorizontalWhitespace: Bool { assert(_isASCII) - return self == _space || self == _tab + return self == ._space || self == ._tab } /// Assuming we're ASCII, whether we match `\v` var _asciiIsVerticalWhitespace: Bool { assert(_isASCII) switch self { - case _lineFeed, _carriageReturn, _lineTab, _formFeed: + case ._lineFeed, ._carriageReturn, ._lineTab, ._formFeed: return true default: return false @@ -61,7 +60,7 @@ extension UInt8 { var _asciiIsWhitespace: Bool { assert(_isASCII) switch self { - case _space, _tab, _lineFeed, _lineTab, _formFeed, _carriageReturn: + case ._space, ._tab, ._lineFeed, ._lineTab, ._formFeed, ._carriageReturn: return true default: return false @@ -77,11 +76,13 @@ extension UInt8 { /// Assuming we're ASCII, whether we match `\w` var _asciiIsWord: Bool { assert(_isASCII) - return _asciiIsDigit || _asciiIsLetter || self == _underscore + return _asciiIsDigit || _asciiIsLetter || self == ._underscore } } extension String { + /// TODO: better to take isScalarSemantics parameter, we can return more results + /// and we can give the right `next` index, not requiring the caller to re-adjust it /// TODO: detailed description of nuanced semantics func _quickASCIICharacter( at idx: Index @@ -107,7 +108,7 @@ extension String { guard tail._isSub300StartingByte else { return nil } // Handle CR-LF: - if base == _carriageReturn && tail == _lineFeed { + if base == ._carriageReturn && tail == ._lineFeed { utf8.formIndex(after: &next) guard next == endIndex || utf8[next]._isSub300StartingByte else { return nil @@ -165,5 +166,6 @@ extension String { return (next, asciiValue._asciiIsWord) } } + } From 9ea993651f0d6a506228368894c392ffd83559bd Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 11 Apr 2023 14:41:09 -0500 Subject: [PATCH 26/34] Avoid long expression type checks (#657) These changes remove several seconds of type-checking time from the RegexBuilder test cases, bringing all expressions under 150ms (on the tested computer). --- Tests/RegexBuilderTests/AlgorithmsTests.swift | 2 +- Tests/RegexBuilderTests/CustomTests.swift | 4 ++-- Tests/RegexBuilderTests/RegexDSLTests.swift | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index 115941070..b85395d19 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -16,7 +16,7 @@ import RegexBuilder @available(SwiftStdlib 5.7, *) class RegexConsumerTests: XCTestCase { func testMatches() { - let regex = Capture(OneOrMore(.digit)) { 2 * Int($0)! } + let regex = Capture<(Substring, Int)>(OneOrMore(.digit)) { 2 * Int($0)! } let str = "foo 160 bar 99 baz" XCTAssertEqual(str.matches(of: regex).map(\.output.1), [320, 198]) } diff --git a/Tests/RegexBuilderTests/CustomTests.swift b/Tests/RegexBuilderTests/CustomTests.swift index 26746d613..848ef4626 100644 --- a/Tests/RegexBuilderTests/CustomTests.swift +++ b/Tests/RegexBuilderTests/CustomTests.swift @@ -64,7 +64,7 @@ private struct IntParser: CustomConsumingRegexComponent { guard index != bounds.upperBound else { return nil } let r = Regex { - Capture(OneOrMore(.digit)) { Int($0) } + Capture<(Substring, Int?)>(OneOrMore(.digit)) { Int($0) } } guard let match = input[index..(Repeat(.digit, count: 2)) { Int($0) } } } diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 5e85ad26c..19ac675dc 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -1091,7 +1091,7 @@ class RegexDSLTests: XCTestCase { OneOrMore("a") Capture { TryCapture("b", transform: { Int($0) }) - ZeroOrMore( + ZeroOrMore<(Substring, Double?)>( TryCapture("c", transform: { Double($0) }) ) Optionally("e") @@ -1542,12 +1542,12 @@ class RegexDSLTests: XCTestCase { in bounds: Range ) throws -> (upperBound: String.Index, output: SemanticVersion)? { let regex = Regex { - TryCapture(OneOrMore(.digit)) { Int($0) } + TryCapture<(Substring, Int)>(OneOrMore(.digit)) { Int($0) } "." - TryCapture(OneOrMore(.digit)) { Int($0) } + TryCapture<(Substring, Int)>(OneOrMore(.digit)) { Int($0) } Optionally { "." - TryCapture(OneOrMore(.digit)) { Int($0) } + TryCapture<(Substring, Int)>(OneOrMore(.digit)) { Int($0) } } Optionally { "-" @@ -1876,7 +1876,7 @@ extension RegexDSLTests { ":" regexWithTooManyCaptures ":" - TryCapture(OneOrMore(.word)) { Int($0) } + TryCapture<(Substring, Int)>(OneOrMore(.word)) { Int($0) } #/:(\d+):/# } XCTAssert(type(of: dslWithTooManyCaptures).self From 58626cc66494827556ca555c9a22ec751848f0b0 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Fri, 14 Apr 2023 09:26:25 -0600 Subject: [PATCH 27/34] Processor cleanup (#655) Clean up and refactor the processor * Simplify instruction fetching * Refactor metrics out, and void their storage in release builds *Put operations onto String --- .../_StringProcessing/Engine/MEBuiltins.swift | 4 + .../_StringProcessing/Engine/MEQuantify.swift | 11 +- .../_StringProcessing/Engine/Metrics.swift | 67 ++++++- .../_StringProcessing/Engine/Processor.swift | 179 ++++++++++++------ .../_StringProcessing/Engine/Tracing.swift | 5 + Sources/_StringProcessing/Executor.swift | 4 +- .../Unicode/WordBreaking.swift | 4 + .../_StringProcessing/Utility/Protocols.swift | 10 - .../_StringProcessing/Utility/Traced.swift | 2 +- 9 files changed, 210 insertions(+), 76 deletions(-) diff --git a/Sources/_StringProcessing/Engine/MEBuiltins.swift b/Sources/_StringProcessing/Engine/MEBuiltins.swift index 4ec7a71dd..b50d1c213 100644 --- a/Sources/_StringProcessing/Engine/MEBuiltins.swift +++ b/Sources/_StringProcessing/Engine/MEBuiltins.swift @@ -30,6 +30,7 @@ extension Processor { } func isAtStartOfLine(_ payload: AssertionPayload) -> Bool { + // TODO: needs benchmark coverage if currentPosition == subjectBounds.lowerBound { return true } switch payload.semanticLevel { case .graphemeCluster: @@ -40,6 +41,7 @@ extension Processor { } func isAtEndOfLine(_ payload: AssertionPayload) -> Bool { + // TODO: needs benchmark coverage if currentPosition == subjectBounds.upperBound { return true } switch payload.semanticLevel { case .graphemeCluster: @@ -50,6 +52,8 @@ extension Processor { } mutating func builtinAssert(by payload: AssertionPayload) throws -> Bool { + // TODO: needs benchmark coverage + // Future work: Optimize layout and dispatch switch payload.kind { case .startOfSubject: return currentPosition == subjectBounds.lowerBound diff --git a/Sources/_StringProcessing/Engine/MEQuantify.swift b/Sources/_StringProcessing/Engine/MEQuantify.swift index 0e2f3923a..81b80b00e 100644 --- a/Sources/_StringProcessing/Engine/MEQuantify.swift +++ b/Sources/_StringProcessing/Engine/MEQuantify.swift @@ -3,10 +3,14 @@ extension Processor { var next: Input.Index? switch payload.type { case .bitset: - next = _doMatchBitset(registers[payload.bitset]) + next = input.matchBitset( + registers[payload.bitset], at: currentPosition, limitedBy: end) case .asciiChar: - next = _doMatchScalar( - UnicodeScalar.init(_value: UInt32(payload.asciiChar)), true) + next = input.matchScalar( + UnicodeScalar.init(_value: UInt32(payload.asciiChar)), + at: currentPosition, + limitedBy: end, + boundaryCheck: true) case .builtin: // We only emit .quantify if it consumes a single character next = input._matchBuiltinCC( @@ -16,6 +20,7 @@ extension Processor { isStrictASCII: payload.builtinIsStrict, isScalarSemantics: false) case .any: + // TODO: call out to existing code with quick check let matched = currentPosition != input.endIndex && (!input[currentPosition].isNewline || payload.anyMatchesNewline) next = matched ? input.index(after: currentPosition) : nil diff --git a/Sources/_StringProcessing/Engine/Metrics.swift b/Sources/_StringProcessing/Engine/Metrics.swift index 753c3c3d1..372a7e1b4 100644 --- a/Sources/_StringProcessing/Engine/Metrics.swift +++ b/Sources/_StringProcessing/Engine/Metrics.swift @@ -1,13 +1,71 @@ extension Processor { +#if PROCESSOR_MEASUREMENTS_ENABLED struct ProcessorMetrics { var instructionCounts: [Instruction.OpCode: Int] = [:] var backtracks: Int = 0 var resets: Int = 0 + var cycleCount: Int = 0 + + var isTracingEnabled: Bool = false + var shouldMeasureMetrics: Bool = false + + init(isTracingEnabled: Bool, shouldMeasureMetrics: Bool) { + self.isTracingEnabled = isTracingEnabled + self.shouldMeasureMetrics = shouldMeasureMetrics + } } - +#else + struct ProcessorMetrics { + var isTracingEnabled: Bool { false } + var shouldMeasureMetrics: Bool { false } + var cycleCount: Int { 0 } + + init(isTracingEnabled: Bool, shouldMeasureMetrics: Bool) { } + } +#endif +} + +extension Processor { + + mutating func startCycleMetrics() { +#if PROCESSOR_MEASUREMENTS_ENABLED + if metrics.cycleCount == 0 { + trace() + measureMetrics() + } +#endif + } + + mutating func endCycleMetrics() { +#if PROCESSOR_MEASUREMENTS_ENABLED + metrics.cycleCount += 1 + trace() + measureMetrics() + _checkInvariants() +#endif + } +} + +extension Processor.ProcessorMetrics { + + mutating func addReset() { +#if PROCESSOR_MEASUREMENTS_ENABLED + self.resets += 1 +#endif + } + + mutating func addBacktrack() { +#if PROCESSOR_MEASUREMENTS_ENABLED + self.backtracks += 1 +#endif + } +} + +extension Processor { +#if PROCESSOR_MEASUREMENTS_ENABLED func printMetrics() { print("===") - print("Total cycle count: \(cycleCount)") + print("Total cycle count: \(metrics.cycleCount)") print("Backtracks: \(metrics.backtracks)") print("Resets: \(metrics.resets)") print("Instructions:") @@ -21,7 +79,7 @@ extension Processor { } mutating func measure() { - let (opcode, _) = fetch().destructure + let (opcode, _) = fetch() if metrics.instructionCounts.keys.contains(opcode) { metrics.instructionCounts[opcode]! += 1 } else { @@ -30,8 +88,9 @@ extension Processor { } mutating func measureMetrics() { - if shouldMeasureMetrics { + if metrics.shouldMeasureMetrics { measure() } } +#endif } diff --git a/Sources/_StringProcessing/Engine/Processor.swift b/Sources/_StringProcessing/Engine/Processor.swift index 98aee7803..3ff767207 100644 --- a/Sources/_StringProcessing/Engine/Processor.swift +++ b/Sources/_StringProcessing/Engine/Processor.swift @@ -86,11 +86,7 @@ struct Processor { var failureReason: Error? = nil - // MARK: Metrics, debugging, etc. - var cycleCount = 0 - var isTracingEnabled: Bool - let shouldMeasureMetrics: Bool - var metrics: ProcessorMetrics = ProcessorMetrics() + var metrics: ProcessorMetrics } extension Processor { @@ -116,8 +112,11 @@ extension Processor { self.subjectBounds = subjectBounds self.searchBounds = searchBounds self.matchMode = matchMode - self.isTracingEnabled = isTracingEnabled - self.shouldMeasureMetrics = shouldMeasureMetrics + + self.metrics = ProcessorMetrics( + isTracingEnabled: isTracingEnabled, + shouldMeasureMetrics: shouldMeasureMetrics) + self.currentPosition = searchBounds.lowerBound // Initialize registers with end of search bounds @@ -144,8 +143,8 @@ extension Processor { self.state = .inProgress self.failureReason = nil - - if shouldMeasureMetrics { metrics.resets += 1 } + + metrics.addReset() _checkInvariants() } @@ -160,6 +159,10 @@ extension Processor { } extension Processor { + func fetch() -> (Instruction.OpCode, Instruction.Payload) { + instructions[controller.pc].destructure + } + var slice: Input.SubSequence { // TODO: Should we whole-scale switch to slices, or // does that depend on options for some anchors? @@ -177,6 +180,7 @@ extension Processor { // Returns whether the advance succeeded. On failure, our // save point was restored mutating func consume(_ n: Distance) -> Bool { + // TODO: need benchmark coverage guard let idx = input.index( currentPosition, offsetBy: n.rawValue, limitedBy: end ) else { @@ -189,6 +193,7 @@ extension Processor { // Advances in unicode scalar view mutating func consumeScalar(_ n: Distance) -> Bool { + // TODO: need benchmark coverage guard let idx = input.unicodeScalars.index( currentPosition, offsetBy: n.rawValue, limitedBy: end ) else { @@ -220,24 +225,22 @@ extension Processor { func load() -> Element? { currentPosition < end ? input[currentPosition] : nil } - func load(count: Int) -> Input.SubSequence? { - let slice = self.slice[currentPosition...].prefix(count) - guard slice.count == count else { return nil } - return slice - } // Match against the current input element. Returns whether // it succeeded vs signaling an error. mutating func match(_ e: Element) -> Bool { - guard let cur = load(), cur == e else { + guard let next = input.match( + e, at: currentPosition, limitedBy: end + ) else { signalFailure() return false } - _uncheckedForcedConsumeOne() + currentPosition = next return true } mutating func matchCaseInsensitive(_ e: Element) -> Bool { + // TODO: need benchmark coverage guard let cur = load(), cur.lowercased() == e.lowercased() else { signalFailure() return false @@ -253,15 +256,21 @@ extension Processor { isScalarMode: Bool ) -> Bool { if isScalarMode { + // TODO: needs benchmark coverage for s in seq.unicodeScalars { guard matchScalar(s, boundaryCheck: false) else { return false } } return true } - for e in seq { - guard match(e) else { return false } + guard let next = input.matchSeq( + seq, at: currentPosition, limitedBy: end + ) else { + signalFailure() + return false } + + currentPosition = next return true } @@ -269,21 +278,10 @@ extension Processor { currentPosition < end ? input.unicodeScalars[currentPosition] : nil } - func _doMatchScalar(_ s: Unicode.Scalar, _ boundaryCheck: Bool) -> Input.Index? { - if s == loadScalar(), - let idx = input.unicodeScalars.index( - currentPosition, - offsetBy: 1, - limitedBy: end), - (!boundaryCheck || input.isOnGraphemeClusterBoundary(idx)) { - return idx - } else { - return nil - } - } - mutating func matchScalar(_ s: Unicode.Scalar, boundaryCheck: Bool) -> Bool { - guard let next = _doMatchScalar(s, boundaryCheck) else { + guard let next = input.matchScalar( + s, at: currentPosition, limitedBy: end, boundaryCheck: boundaryCheck + ) else { signalFailure() return false } @@ -295,6 +293,7 @@ extension Processor { _ s: Unicode.Scalar, boundaryCheck: Bool ) -> Bool { + // TODO: needs benchmark coverage guard let curScalar = loadScalar(), s.properties.lowercaseMapping == curScalar.properties.lowercaseMapping, let idx = input.unicodeScalars.index( @@ -310,21 +309,15 @@ extension Processor { return true } - func _doMatchBitset(_ bitset: DSLTree.CustomCharacterClass.AsciiBitset) -> Input.Index? { - if let cur = load(), bitset.matches(char: cur) { - return input.index(after: currentPosition) - } else { - return nil - } - } - // If we have a bitset we know that the CharacterClass only matches against // ascii characters, so check if the current input element is ascii then // check if it is set in the bitset mutating func matchBitset( _ bitset: DSLTree.CustomCharacterClass.AsciiBitset ) -> Bool { - guard let next = _doMatchBitset(bitset) else { + guard let next = input.matchBitset( + bitset, at: currentPosition, limitedBy: end + ) else { signalFailure() return false } @@ -336,6 +329,7 @@ extension Processor { mutating func matchBitsetScalar( _ bitset: DSLTree.CustomCharacterClass.AsciiBitset ) -> Bool { + // TODO: needs benchmark coverage guard let curScalar = loadScalar(), bitset.matches(scalar: curScalar), let idx = input.unicodeScalars.index(currentPosition, offsetBy: 1, limitedBy: end) else { @@ -396,8 +390,8 @@ extension Processor { storedCaptures = capEnds registers.ints = intRegisters registers.positions = posRegisters - - if shouldMeasureMetrics { metrics.backtracks += 1 } + + metrics.addBacktrack() } mutating func abort(_ e: Error? = nil) { @@ -436,20 +430,10 @@ extension Processor { _checkInvariants() assert(state == .inProgress) -#if PROCESSOR_MEASUREMENTS_ENABLED - if cycleCount == 0 { - trace() - measureMetrics() - } - defer { - cycleCount += 1 - trace() - measureMetrics() - _checkInvariants() - } -#endif + startCycleMetrics() + defer { endCycleMetrics() } - let (opcode, payload) = fetch().destructure + let (opcode, payload) = fetch() switch opcode { case .invalid: fatalError("Invalid program") @@ -703,3 +687,86 @@ extension Processor { } } } + +extension String { + + func match( + _ char: Character, + at pos: Index, + limitedBy end: String.Index + ) -> Index? { + // TODO: This can be greatly sped up with string internals + // TODO: This is also very much quick-check-able + assert(end <= endIndex) + + guard pos < end, self[pos] == char else { return nil } + + let idx = index(after: pos) + guard idx <= end else { return nil } + + return idx + } + + func matchSeq( + _ seq: Substring, + at pos: Index, + limitedBy end: Index + ) -> Index? { + // TODO: This can be greatly sped up with string internals + // TODO: This is also very much quick-check-able + assert(end <= endIndex) + + var cur = pos + for e in seq { + guard cur < end, self[cur] == e else { return nil } + self.formIndex(after: &cur) + } + + guard cur <= end else { return nil } + return cur + } + + func matchScalar( + _ scalar: Unicode.Scalar, + at pos: Index, + limitedBy end: String.Index, + boundaryCheck: Bool + ) -> Index? { + assert(end <= endIndex) + + guard pos < end, unicodeScalars[pos] == scalar else { + return nil + } + + let idx = unicodeScalars.index(after: pos) + guard idx <= end else { return nil } + + if boundaryCheck && !isOnGraphemeClusterBoundary(idx) { + return nil + } + + return idx + } + + func matchBitset( + _ bitset: DSLTree.CustomCharacterClass.AsciiBitset, + at pos: Index, + limitedBy end: Index + ) -> Index? { + // TODO: extremely quick-check-able + // TODO: can be sped up with string internals + + assert(end <= endIndex) + + guard pos < end, bitset.matches(char: self[pos]) else { + return nil + } + + let idx = index(after: pos) + guard idx <= end else { return nil } + + return idx + } + + +} diff --git a/Sources/_StringProcessing/Engine/Tracing.swift b/Sources/_StringProcessing/Engine/Tracing.swift index 725319b00..b0ce67555 100644 --- a/Sources/_StringProcessing/Engine/Tracing.swift +++ b/Sources/_StringProcessing/Engine/Tracing.swift @@ -9,7 +9,12 @@ // //===----------------------------------------------------------------------===// + +// TODO: Remove this protocol (and/or reuse it for something like a FastProcessor) extension Processor: TracedProcessor { + var cycleCount: Int { metrics.cycleCount } + var isTracingEnabled: Bool { metrics.isTracingEnabled } + var isFailState: Bool { state == .fail } var isAcceptState: Bool { state == .accept } diff --git a/Sources/_StringProcessing/Executor.swift b/Sources/_StringProcessing/Executor.swift index 253858d1f..0453fcd80 100644 --- a/Sources/_StringProcessing/Executor.swift +++ b/Sources/_StringProcessing/Executor.swift @@ -31,7 +31,7 @@ struct Executor { subjectBounds: subjectBounds, searchBounds: searchBounds) #if PROCESSOR_MEASUREMENTS_ENABLED - defer { if cpu.shouldMeasureMetrics { cpu.printMetrics() } } + defer { if cpu.metrics.shouldMeasureMetrics { cpu.printMetrics() } } #endif var low = searchBounds.lowerBound let high = searchBounds.upperBound @@ -60,7 +60,7 @@ struct Executor { var cpu = engine.makeProcessor( input: input, bounds: subjectBounds, matchMode: mode) #if PROCESSOR_MEASUREMENTS_ENABLED - defer { if cpu.shouldMeasureMetrics { cpu.printMetrics() } } + defer { if cpu.metrics.shouldMeasureMetrics { cpu.printMetrics() } } #endif return try _match(input, from: subjectBounds.lowerBound, using: &cpu) } diff --git a/Sources/_StringProcessing/Unicode/WordBreaking.swift b/Sources/_StringProcessing/Unicode/WordBreaking.swift index 50da079f6..f1f9573c1 100644 --- a/Sources/_StringProcessing/Unicode/WordBreaking.swift +++ b/Sources/_StringProcessing/Unicode/WordBreaking.swift @@ -12,6 +12,7 @@ @_spi(_Unicode) import Swift +// TODO: Sink onto String extension Processor { func atSimpleBoundary( _ usesAsciiWord: Bool, @@ -20,9 +21,11 @@ extension Processor { func matchesWord(at i: Input.Index) -> Bool { switch semanticLevel { case .graphemeCluster: + // TODO: needs benchmark coverage let c = input[i] return c.isWordCharacter && (c.isASCII || !usesAsciiWord) case .unicodeScalar: + // TODO: needs benchmark coverage let c = input.unicodeScalars[i] return (c.properties.isAlphabetic || c == "_") && (c.isASCII || !usesAsciiWord) } @@ -51,6 +54,7 @@ extension String { using cache: inout Set?, _ maxIndex: inout String.Index? ) -> Bool { + // TODO: needs benchmark coverage guard i != startIndex, i != endIndex else { return true } diff --git a/Sources/_StringProcessing/Utility/Protocols.swift b/Sources/_StringProcessing/Utility/Protocols.swift index 7542a17dd..24ffbcf70 100644 --- a/Sources/_StringProcessing/Utility/Protocols.swift +++ b/Sources/_StringProcessing/Utility/Protocols.swift @@ -44,13 +44,3 @@ protocol ProcessorProtocol { var registers: Registers { get } } -extension ProcessorProtocol { - func fetch() -> Instruction { - instructions[currentPC] - } - - var callStack: Array { [] } -// var savePoints: Array { [] } - var registers: Array { [] } - -} diff --git a/Sources/_StringProcessing/Utility/Traced.swift b/Sources/_StringProcessing/Utility/Traced.swift index 112a601b1..198564fe1 100644 --- a/Sources/_StringProcessing/Utility/Traced.swift +++ b/Sources/_StringProcessing/Utility/Traced.swift @@ -13,7 +13,7 @@ // TODO: Place shared formatting and trace infrastructure here protocol Traced { - var isTracingEnabled: Bool { get set } + var isTracingEnabled: Bool { get } } protocol TracedProcessor: ProcessorProtocol, Traced { From 4418183cfcbf13ebb0bb7e7989ec3e47d885b40d Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Fri, 14 Apr 2023 15:19:05 -0500 Subject: [PATCH 28/34] Fix `firstRange(of:)` search (#656) Calls to `ranges(of:)` and `firstRange(of:)` with a string parameter actually use two different string searching algorithms. `ranges(of:)` uses the "z-searcher" algorithm, while `firstRange(of:)` uses a two-way search. Since it's better to align on a single path for these searches, the z-searcher has lower requirements, and the two-way search implementation has a correctness bug, this change removes the two-way search algorithm and uses z-search for `firstRange(of:)`. The correctness bug in `firstRange(of:)` appears only when searching for the second (or later) occurrence of a substring, which you have to be fairly deliberate about. In the example below, the substring at offsets `7..<12` is missed: let text = "ADACBADADACBADACB" // ===== -----===== let pattern = "ADACB" let firstRange = text.firstRange(of: pattern)! // firstRange ~= 0..<5 let secondRange = text[firstRange.upperBound...].firstRange(of: pattern)! // secondRange ~= 12..<17 This change also removes some unrelated, unused code in Split.swift, in addition to removing an (unused) usage of `TwoWaySearcher`. rdar://92794248 --- .../Algorithms/Algorithms/FirstRange.swift | 7 +- .../Algorithms/Algorithms/Split.swift | 60 ------ .../Algorithms/Searchers/TwoWaySearcher.swift | 197 ------------------ Sources/_StringProcessing/CMakeLists.txt | 1 - Tests/RegexTests/AlgorithmsTests.swift | 11 +- 5 files changed, 11 insertions(+), 265 deletions(-) delete mode 100644 Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index 484ff4648..d0fb8673d 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -50,11 +50,8 @@ extension BidirectionalCollection where Element: Comparable { public func firstRange( of other: C ) -> Range? where C.Element == Element { - let searcher = PatternOrEmpty( - searcher: TwoWaySearcher(pattern: Array(other))) - let slice = self[...] - var state = searcher.state(for: slice, in: startIndex..(pattern: Array(other), by: ==) + return searcher.search(self[...], in: startIndex.. Bool, - maxSplits: Int, - omittingEmptySubsequences: Bool - ) -> SplitCollection> { - split(by: PredicateConsumer(predicate: predicate), maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) - } -} - -// MARK: Single element algorithms - -extension Collection where Element: Equatable { - func split( - by separator: Element, - maxSplits: Int, - omittingEmptySubsequences: Bool - ) -> SplitCollection> { - split(whereSeparator: { $0 == separator }, maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) - } -} - // MARK: Fixed pattern algorithms extension Collection where Element: Equatable { @@ -180,41 +155,6 @@ extension Collection where Element: Equatable { } } -extension BidirectionalCollection where Element: Equatable { - // FIXME -// public func splitFromBack( -// separator: S -// ) -> ReversedSplitCollection> -// where S.Element == Element -// { -// splitFromBack(separator: ZSearcher(pattern: Array(separator), by: ==)) -// } -} - -extension BidirectionalCollection where Element: Comparable { - func split( - by separator: C, - maxSplits: Int, - omittingEmptySubsequences: Bool - ) -> SplitCollection>> - where C.Element == Element - { - split( - by: PatternOrEmpty(searcher: TwoWaySearcher(pattern: Array(separator))), - maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) - } - - // FIXME -// public func splitFromBack( -// separator: S -// ) -> ReversedSplitCollection>> -// where S.Element == Element -// { -// splitFromBack(separator: PatternOrEmpty( -// searcher: TwoWaySearcher(pattern: Array(separator)))) -// } -} - // String split overload breakers // // These are underscored and marked as SPI so that the *actual* public overloads diff --git a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift b/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift deleted file mode 100644 index 2428f89cd..000000000 --- a/Sources/_StringProcessing/Algorithms/Searchers/TwoWaySearcher.swift +++ /dev/null @@ -1,197 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// -//===----------------------------------------------------------------------===// - -extension BidirectionalCollection where Element: Equatable { - fileprivate func _ends(with suffix: C) -> Bool - where C.Element == Element - { - FixedPatternConsumer(pattern: suffix).consumingBack(self[...]) != nil - } - } - -struct TwoWaySearcher - where Searched.Element: Comparable -{ - // TODO: Be generic over the pattern? - let pattern: [Searched.Element] - let criticalIndex: Int - let period: Int - let periodIsExact: Bool - - init?(pattern: [Searched.Element]) { - guard !pattern.isEmpty else { return nil } - - let (criticalIndex, periodOfSecondPart) = pattern._criticalFactorization(<) - let periodIsExact = pattern[criticalIndex...] - .prefix(periodOfSecondPart) - ._ends(with: pattern[.. - ) -> State { - // FIXME: Is this 'limitedBy' requirement a sign of error? - let criticalIndex = searched.index( - range.lowerBound, offsetBy: criticalIndex, limitedBy: range.upperBound) - ?? range.upperBound - return State( - end: range.upperBound, - index: range.lowerBound, - criticalIndex: - criticalIndex, - memory: nil) - } - - func search( - _ searched: Searched, - _ state: inout State - ) -> Range? { - while state.criticalIndex != searched.endIndex { - if let end = _searchRight(searched, &state), - let start = _searchLeft(searched, &state, end) - { - state.index = end - // FIXME: Is this 'limitedBy' requirement a sign of error? - state.criticalIndex = searched.index( - end, offsetBy: criticalIndex, limitedBy: searched.endIndex) - ?? searched.endIndex - state.memory = nil - return start.. Searched.Index? { - let rStart: Int - var rIndex: Searched.Index - - if let memory = state.memory, memory.offset > criticalIndex { - rStart = memory.offset - rIndex = memory.index - } else { - rStart = criticalIndex - rIndex = state.criticalIndex - } - - for i in rStart.. Searched.Index? { - let lStart = min(state.memory?.offset ?? 0, criticalIndex) - var lIndex = state.criticalIndex - - for i in (lStart.. Bool - ) -> (index: Int, periodOfSecondPart: Int) { - let less = _maximalSuffix(isOrderedBefore) - let greater = _maximalSuffix({ isOrderedBefore($1, $0) }) - return less.index > greater.index ? less : greater - } - - func _maximalSuffix( - _ isOrderedBefore: (Element, Element) -> Bool - ) -> (index: Int, periodOfSecondPart: Int) { - var left = 0 - var right = 1 - var offset = 0 - var period = 1 - - while right + offset < count { - let a = self[right + offset] - let b = self[left + offset] - - if isOrderedBefore(a, b) { - // Suffix is smaller, period is entire prefix so far. - right += offset + 1 - offset = 0 - period = right - left - } else if isOrderedBefore(b, a) { - // Suffix is larger, start over from current location. - left = right - right += 1 - offset = 0 - period = 1 - } else { - // Advance through repetition of the current period. - offset += 1 - if offset + 1 == period { - right += offset + 1 - offset = 0 - } else { - offset += 1 - } - } - } - - return (left, period) - } -} diff --git a/Sources/_StringProcessing/CMakeLists.txt b/Sources/_StringProcessing/CMakeLists.txt index ef4aeb6ef..f7ccd7ab9 100644 --- a/Sources/_StringProcessing/CMakeLists.txt +++ b/Sources/_StringProcessing/CMakeLists.txt @@ -23,7 +23,6 @@ add_library(_StringProcessing Algorithms/Searchers/NaivePatternSearcher.swift Algorithms/Searchers/PatternOrEmpty.swift Algorithms/Searchers/PredicateSearcher.swift - Algorithms/Searchers/TwoWaySearcher.swift Algorithms/Searchers/ZSearcher.swift Engine/Backtracking.swift Engine/Consume.swift diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index d5419fe9c..60548a0a2 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -165,8 +165,12 @@ class AlgorithmTests: XCTestCase { let actualCol: [Range] = input.ranges(of: pattern)[...].map(input.offsets(of:)) XCTAssertEqual(actualCol, expected, file: file, line: line) - let firstRange = input.firstRange(of: pattern).map(input.offsets(of:)) - XCTAssertEqual(firstRange, expected.first, file: file, line: line) + let firstRange = input.firstRange(of: pattern) + XCTAssertEqual(firstRange.map(input.offsets(of:)), expected.first, file: file, line: line) + if let upperBound = firstRange?.upperBound, !pattern.isEmpty { + let secondRange = input[upperBound...].firstRange(of: pattern).map(input.offsets(of:)) + XCTAssertEqual(secondRange, expected.dropFirst().first, file: file, line: line) + } } expectRanges("", "", [0..<0]) @@ -176,6 +180,9 @@ class AlgorithmTests: XCTestCase { expectRanges("abcde", "bcd", [1..<4]) expectRanges("ababacabababa", "abababa", [6..<13]) expectRanges("ababacabababa", "aba", [0..<3, 6..<9, 10..<13]) + + // Test for rdar://92794248 + expectRanges("ADACBADADACBADACB", "ADACB", [0..<5, 7..<12, 12..<17]) } // rdar://105154010 From 57b343ddf9262f397366d005027f47b83d0fa5b6 Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Tue, 18 Apr 2023 11:41:20 -0600 Subject: [PATCH 29/34] Bug fix and hot path for quantified `.` (#658) Bug fix in newline hot path, and apply hot path to quantified dot --- .../_StringProcessing/Engine/MEBuiltins.swift | 16 +++++++------ .../_StringProcessing/Engine/MEQuantify.swift | 24 ++++++++++++------- Tests/RegexTests/MatchTests.swift | 5 ++++ 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/Sources/_StringProcessing/Engine/MEBuiltins.swift b/Sources/_StringProcessing/Engine/MEBuiltins.swift index b50d1c213..d8c8c347b 100644 --- a/Sources/_StringProcessing/Engine/MEBuiltins.swift +++ b/Sources/_StringProcessing/Engine/MEBuiltins.swift @@ -63,10 +63,10 @@ extension Processor { switch payload.semanticLevel { case .graphemeCluster: return input.index(after: currentPosition) == subjectBounds.upperBound - && input[currentPosition].isNewline + && input[currentPosition].isNewline case .unicodeScalar: return input.unicodeScalars.index(after: currentPosition) == subjectBounds.upperBound - && input.unicodeScalars[currentPosition].isNewline + && input.unicodeScalars[currentPosition].isNewline } case .endOfSubject: return currentPosition == subjectBounds.upperBound @@ -121,6 +121,7 @@ extension Processor { // MARK: Matching `.` extension String { + // TODO: Should the below have a `limitedBy` parameter? func _matchAnyNonNewline( at currentPosition: String.Index, @@ -155,11 +156,11 @@ extension String { return .unknown } switch asciiValue { - case ._lineFeed, ._carriageReturn: - return .definite(nil) - default: - assert(!isCRLF) - return .definite(next) + case (._lineFeed)...(._carriageReturn): + return .definite(nil) + default: + assert(!isCRLF) + return .definite(next) } } @@ -183,6 +184,7 @@ extension String { // MARK: - Built-in character class matching extension String { + // TODO: Should the below have a `limitedBy` parameter? // Mentioned in ProgrammersManual.md, update docs if redesigned func _matchBuiltinCC( diff --git a/Sources/_StringProcessing/Engine/MEQuantify.swift b/Sources/_StringProcessing/Engine/MEQuantify.swift index 81b80b00e..873627567 100644 --- a/Sources/_StringProcessing/Engine/MEQuantify.swift +++ b/Sources/_StringProcessing/Engine/MEQuantify.swift @@ -1,31 +1,37 @@ extension Processor { func _doQuantifyMatch(_ payload: QuantifyPayload) -> Input.Index? { - var next: Input.Index? + // FIXME: is the below updated for scalar semantics? switch payload.type { case .bitset: - next = input.matchBitset( + return input.matchBitset( registers[payload.bitset], at: currentPosition, limitedBy: end) case .asciiChar: - next = input.matchScalar( + return input.matchScalar( UnicodeScalar.init(_value: UInt32(payload.asciiChar)), at: currentPosition, limitedBy: end, boundaryCheck: true) case .builtin: + // FIXME: bounds check? endIndex or end? + // We only emit .quantify if it consumes a single character - next = input._matchBuiltinCC( + return input._matchBuiltinCC( payload.builtin, at: currentPosition, isInverted: payload.builtinIsInverted, isStrictASCII: payload.builtinIsStrict, isScalarSemantics: false) case .any: - // TODO: call out to existing code with quick check - let matched = currentPosition != input.endIndex - && (!input[currentPosition].isNewline || payload.anyMatchesNewline) - next = matched ? input.index(after: currentPosition) : nil + // FIXME: endIndex or end? + guard currentPosition < input.endIndex else { return nil } + + if payload.anyMatchesNewline { + return input.index(after: currentPosition) + } + + return input._matchAnyNonNewline( + at: currentPosition, isScalarSemantics: false) } - return next } /// Generic quantify instruction interpreter diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index e8e41a114..a6c9babbe 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -1891,6 +1891,11 @@ extension RegexTests { func testSingleLineMode() { firstMatchTest(#".+"#, input: "a\nb", match: "a") firstMatchTest(#"(?s:.+)"#, input: "a\nb", match: "a\nb") + + // We recognize LF, line tab, FF, and CR as newlines by default + firstMatchTest(#"."#, input: "\u{A}\u{B}\u{C}\u{D}\nb", match: "b") + firstMatchTest(#".+"#, input: "\u{A}\u{B}\u{C}\u{D}\nbb", match: "bb") + } func testMatchNewlines() { From 6695027e5de5f9c2d9418414aa4d2317926e964e Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Tue, 18 Apr 2023 11:42:36 -0600 Subject: [PATCH 30/34] Run scalar-semantic benchmark variants (#659) Run scalar semantic benchmarks --- Sources/RegexBenchmark/Benchmark.swift | 92 +++++------ Sources/RegexBenchmark/BenchmarkRunner.swift | 143 +++++++++++++++++- .../Suite/CustomCharacterClasses.swift | 72 ++++----- 3 files changed, 213 insertions(+), 94 deletions(-) diff --git a/Sources/RegexBenchmark/Benchmark.swift b/Sources/RegexBenchmark/Benchmark.swift index 2622639fb..f807a8e55 100644 --- a/Sources/RegexBenchmark/Benchmark.swift +++ b/Sources/RegexBenchmark/Benchmark.swift @@ -71,6 +71,13 @@ struct NSBenchmark: RegexBenchmark { enum NSMatchType { case allMatches case first + + init(_ type: Benchmark.MatchType) { + switch type { + case .whole, .first: self = .first + case .allMatches: self = .allMatches + } + } } func run() { @@ -126,7 +133,7 @@ struct CrossBenchmark { /// The base name of the benchmark var baseName: String - /// The string to compile in differnet engines + /// The string to compile in different engines var regex: String /// The text to search @@ -143,57 +150,32 @@ struct CrossBenchmark { /// Whether or not to do firstMatch as well or just allMatches var includeFirst: Bool = false + /// Whether to also run scalar-semantic mode + var alsoRunScalarSemantic: Bool = true + func register(_ runner: inout BenchmarkRunner) { - let swiftRegex = try! Regex(regex) - let nsRegex: NSRegularExpression if isWhole { - nsRegex = try! NSRegularExpression(pattern: "^" + regex + "$") + runner.registerCrossBenchmark( + nameBase: baseName, + input: input, + pattern: regex, + .whole, + alsoRunScalarSemantic: alsoRunScalarSemantic) } else { - nsRegex = try! NSRegularExpression(pattern: regex) - } + runner.registerCrossBenchmark( + nameBase: baseName, + input: input, + pattern: regex, + .allMatches, + alsoRunScalarSemantic: alsoRunScalarSemantic) - if isWhole { - runner.register( - Benchmark( - name: baseName + "Whole", - regex: swiftRegex, - pattern: regex, - type: .whole, - target: input)) - runner.register( - NSBenchmark( - name: baseName + "Whole" + CrossBenchmark.nsSuffix, - regex: nsRegex, - type: .first, - target: input)) - } else { - runner.register( - Benchmark( - name: baseName + "All", - regex: swiftRegex, - pattern: regex, - type: .allMatches, - target: input)) - runner.register( - NSBenchmark( - name: baseName + "All" + CrossBenchmark.nsSuffix, - regex: nsRegex, - type: .allMatches, - target: input)) if includeFirst || runner.includeFirstOverride { - runner.register( - Benchmark( - name: baseName + "First", - regex: swiftRegex, - pattern: regex, - type: .first, - target: input)) - runner.register( - NSBenchmark( - name: baseName + "First" + CrossBenchmark.nsSuffix, - regex: nsRegex, - type: .first, - target: input)) + runner.registerCrossBenchmark( + nameBase: baseName, + input: input, + pattern: regex, + .first, + alsoRunScalarSemantic: alsoRunScalarSemantic) } } } @@ -209,20 +191,16 @@ struct CrossInputListBenchmark { /// The list of strings to search var inputs: [String] + + /// Also run in scalar-semantic mode + var alsoRunScalarSemantic: Bool = true func register(_ runner: inout BenchmarkRunner) { - let swiftRegex = try! Regex(regex) - runner.register(InputListBenchmark( + runner.registerCrossBenchmark( name: baseName, - regex: swiftRegex, + inputList: inputs, pattern: regex, - targets: inputs - )) - runner.register(InputListNSBenchmark( - name: baseName + CrossBenchmark.nsSuffix, - regex: regex, - targets: inputs - )) + alsoRunScalarSemantic: alsoRunScalarSemantic) } } diff --git a/Sources/RegexBenchmark/BenchmarkRunner.swift b/Sources/RegexBenchmark/BenchmarkRunner.swift index 641c03224..b067b9679 100644 --- a/Sources/RegexBenchmark/BenchmarkRunner.swift +++ b/Sources/RegexBenchmark/BenchmarkRunner.swift @@ -4,6 +4,16 @@ import Foundation /// The number of times to re-run the benchmark if results are too varying private var rerunCount: Int { 3 } +extension Benchmark.MatchType { + fileprivate var nameSuffix: String { + switch self { + case .whole: return "_Whole" + case .first: return "_First" + case .allMatches: return "_All" + } + } +} + struct BenchmarkRunner { let suiteName: String var suite: [any RegexBenchmark] = [] @@ -16,12 +26,141 @@ struct BenchmarkRunner { // Forcibly include firstMatch benchmarks for all CrossBenchmarks let includeFirstOverride: Bool + + // Register a cross-benchmark + mutating func registerCrossBenchmark( + nameBase: String, + input: String, + pattern: String, + _ type: Benchmark.MatchType, + alsoRunScalarSemantic: Bool = true + ) { + let swiftRegex = try! Regex(pattern) + let nsRegex: NSRegularExpression + if type == .whole { + nsRegex = try! NSRegularExpression(pattern: "^" + pattern + "$") + } else { + nsRegex = try! NSRegularExpression(pattern: pattern) + } + let nameSuffix = type.nameSuffix + + register( + Benchmark( + name: nameBase + nameSuffix, + regex: swiftRegex, + pattern: pattern, + type: type, + target: input)) + register( + NSBenchmark( + name: nameBase + nameSuffix + CrossBenchmark.nsSuffix, + regex: nsRegex, + type: .init(type), + target: input)) + + if alsoRunScalarSemantic { + register( + Benchmark( + name: nameBase + nameSuffix + "_Scalar", + regex: swiftRegex.matchingSemantics(.unicodeScalar), + pattern: pattern, + type: type, + target: input)) + register( + NSBenchmark( + name: nameBase + nameSuffix + "_Scalar" + CrossBenchmark.nsSuffix, + regex: nsRegex, + type: .init(type), + target: input)) + } + } + + // Register a cross-benchmark list + mutating func registerCrossBenchmark( + name: String, + inputList: [String], + pattern: String, + alsoRunScalarSemantic: Bool = true + ) { + let swiftRegex = try! Regex(pattern) + register(InputListBenchmark( + name: name, + regex: swiftRegex, + pattern: pattern, + targets: inputList + )) + register(InputListNSBenchmark( + name: name + CrossBenchmark.nsSuffix, + regex: pattern, + targets: inputList + )) + + if alsoRunScalarSemantic { + register(InputListBenchmark( + name: name + "_Scalar", + regex: swiftRegex.matchingSemantics(.unicodeScalar), + pattern: pattern, + targets: inputList + )) + register(InputListNSBenchmark( + name: name + "_Scalar" + CrossBenchmark.nsSuffix, + regex: pattern, + targets: inputList + )) + } + + } + + // Register a swift-only benchmark + mutating func register( + nameBase: String, + input: String, + pattern: String, + _ swiftRegex: Regex, + _ type: Benchmark.MatchType, + alsoRunScalarSemantic: Bool = true + ) { + let nameSuffix = type.nameSuffix + + register( + Benchmark( + name: nameBase + nameSuffix, + regex: swiftRegex, + pattern: pattern, + type: type, + target: input)) + + if alsoRunScalarSemantic { + register( + Benchmark( + name: nameBase + nameSuffix + "_Scalar", + regex: swiftRegex, + pattern: pattern, + type: type, + target: input)) + } + } - mutating func register(_ benchmark: some RegexBenchmark) { + private mutating func register(_ benchmark: NSBenchmark) { suite.append(benchmark) } - mutating func register(_ benchmark: some SwiftRegexBenchmark) { + private mutating func register(_ benchmark: Benchmark) { + var benchmark = benchmark + if enableTracing { + benchmark.enableTracing() + } + if enableMetrics { + benchmark.enableMetrics() + } + suite.append(benchmark) + } + + private mutating func register(_ benchmark: InputListNSBenchmark) { + suite.append(benchmark) + } + + private mutating func register(_ benchmark: InputListBenchmark) { var benchmark = benchmark if enableTracing { benchmark.enableTracing() diff --git a/Sources/RegexBenchmark/Suite/CustomCharacterClasses.swift b/Sources/RegexBenchmark/Suite/CustomCharacterClasses.swift index 61d7b197f..27b2b07b4 100644 --- a/Sources/RegexBenchmark/Suite/CustomCharacterClasses.swift +++ b/Sources/RegexBenchmark/Suite/CustomCharacterClasses.swift @@ -12,53 +12,55 @@ extension BenchmarkRunner { let input = Inputs.graphemeBreakData - register(Benchmark( - name: "BasicCCC", - regex: try! Regex(basic), + // TODO: Which of these can be cross-benchmarks? + + register( + nameBase: "BasicCCC", + input: input, pattern: basic, - type: .allMatches, - target: input)) + try! Regex(basic), + .allMatches) - register(Benchmark( - name: "BasicRangeCCC", - regex: try! Regex(basicRange), + register( + nameBase: "BasicRangeCCC", + input: input, pattern: basicRange, - type: .allMatches, - target: input)) + try! Regex(basicRange), + .allMatches) - register(Benchmark( - name: "CaseInsensitiveCCC", - regex: try! Regex(caseInsensitive), + register( + nameBase: "CaseInsensitiveCCC", + input: input, pattern: caseInsensitive, - type: .allMatches, - target: input)) + try! Regex(caseInsensitive), + .allMatches) - register(Benchmark( - name: "InvertedCCC", - regex: try! Regex(inverted), + register( + nameBase: "InvertedCCC", + input: input, pattern: inverted, - type: .allMatches, - target: input)) + try! Regex(inverted), + .allMatches) - register(Benchmark( - name: "SubtractionCCC", - regex: try! Regex(subtraction), + register( + nameBase: "SubtractionCCC", + input: input, pattern: subtraction, - type: .allMatches, - target: input)) + try! Regex(subtraction), + .allMatches) - register(Benchmark( - name: "IntersectionCCC", - regex: try! Regex(intersection), + register( + nameBase: "IntersectionCCC", + input: input, pattern: intersection, - type: .allMatches, - target: input)) + try! Regex(intersection), + .allMatches) - register(Benchmark( - name: "symDiffCCC", - regex: try! Regex(symmetricDifference), + register( + nameBase: "symDiffCCC", + input: input, pattern: symmetricDifference, - type: .allMatches, - target: input)) + try! Regex(symmetricDifference), + .allMatches) } } From 8eafd55fe3f0e5261c6e92365a6a6c6785670cbc Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Wed, 19 Apr 2023 14:02:57 -0600 Subject: [PATCH 31/34] Refactor operations to be on String (#664) Finish refactoring logic onto String --- Sources/RegexBenchmark/Utils/Stats.swift | 4 +- .../_StringProcessing/Engine/MEBuiltins.swift | 14 +- .../_StringProcessing/Engine/MEQuantify.swift | 18 +- .../_StringProcessing/Engine/Processor.swift | 228 ++++++++---------- .../Utility/AsciiBitset.swift | 4 +- .../_CharacterClassModel.swift | 2 +- 6 files changed, 131 insertions(+), 139 deletions(-) diff --git a/Sources/RegexBenchmark/Utils/Stats.swift b/Sources/RegexBenchmark/Utils/Stats.swift index 0cc9156a4..175826a0b 100644 --- a/Sources/RegexBenchmark/Utils/Stats.swift +++ b/Sources/RegexBenchmark/Utils/Stats.swift @@ -3,8 +3,8 @@ import Foundation enum Stats {} extension Stats { - // Maximum allowed standard deviation is 5% of the median runtime - static let maxAllowedStdev = 0.05 + // Maximum allowed standard deviation is 7.5% of the median runtime + static let maxAllowedStdev = 0.075 static func tTest(_ a: Measurement, _ b: Measurement) -> Bool { // Student's t-test diff --git a/Sources/_StringProcessing/Engine/MEBuiltins.swift b/Sources/_StringProcessing/Engine/MEBuiltins.swift index d8c8c347b..5e446b472 100644 --- a/Sources/_StringProcessing/Engine/MEBuiltins.swift +++ b/Sources/_StringProcessing/Engine/MEBuiltins.swift @@ -15,7 +15,7 @@ extension Processor { isStrictASCII: Bool, isScalarSemantics: Bool ) -> Bool { - guard let next = input._matchBuiltinCC( + guard let next = input.matchBuiltinCC( cc, at: currentPosition, isInverted: isInverted, @@ -123,7 +123,7 @@ extension Processor { extension String { // TODO: Should the below have a `limitedBy` parameter? - func _matchAnyNonNewline( + func matchAnyNonNewline( at currentPosition: String.Index, isScalarSemantics: Bool ) -> String.Index? { @@ -145,7 +145,7 @@ extension String { } @inline(__always) - func _quickMatchAnyNonNewline( + private func _quickMatchAnyNonNewline( at currentPosition: String.Index, isScalarSemantics: Bool ) -> QuickResult { @@ -165,7 +165,7 @@ extension String { } @inline(never) - func _thoroughMatchAnyNonNewline( + private func _thoroughMatchAnyNonNewline( at currentPosition: String.Index, isScalarSemantics: Bool ) -> String.Index? { @@ -187,7 +187,7 @@ extension String { // TODO: Should the below have a `limitedBy` parameter? // Mentioned in ProgrammersManual.md, update docs if redesigned - func _matchBuiltinCC( + func matchBuiltinCC( _ cc: _CharacterClassModel.Representation, at currentPosition: String.Index, isInverted: Bool, @@ -222,7 +222,7 @@ extension String { // Mentioned in ProgrammersManual.md, update docs if redesigned @inline(__always) - func _quickMatchBuiltinCC( + private func _quickMatchBuiltinCC( _ cc: _CharacterClassModel.Representation, at currentPosition: String.Index, isInverted: Bool, @@ -240,7 +240,7 @@ extension String { // Mentioned in ProgrammersManual.md, update docs if redesigned @inline(never) - func _thoroughMatchBuiltinCC( + private func _thoroughMatchBuiltinCC( _ cc: _CharacterClassModel.Representation, at currentPosition: String.Index, isInverted: Bool, diff --git a/Sources/_StringProcessing/Engine/MEQuantify.swift b/Sources/_StringProcessing/Engine/MEQuantify.swift index 873627567..7ca3ae84a 100644 --- a/Sources/_StringProcessing/Engine/MEQuantify.swift +++ b/Sources/_StringProcessing/Engine/MEQuantify.swift @@ -1,21 +1,27 @@ extension Processor { func _doQuantifyMatch(_ payload: QuantifyPayload) -> Input.Index? { - // FIXME: is the below updated for scalar semantics? + // TODO: This optimization is only enabled for grapheme cluster semantics, + // we want these for scalar semantics as well. + switch payload.type { case .bitset: return input.matchBitset( - registers[payload.bitset], at: currentPosition, limitedBy: end) + registers[payload.bitset], + at: currentPosition, + limitedBy: end, + isScalarSemantics: false) case .asciiChar: return input.matchScalar( UnicodeScalar.init(_value: UInt32(payload.asciiChar)), at: currentPosition, limitedBy: end, - boundaryCheck: true) + boundaryCheck: true, + isCaseInsensitive: false) case .builtin: // FIXME: bounds check? endIndex or end? // We only emit .quantify if it consumes a single character - return input._matchBuiltinCC( + return input.matchBuiltinCC( payload.builtin, at: currentPosition, isInverted: payload.builtinIsInverted, @@ -29,7 +35,7 @@ extension Processor { return input.index(after: currentPosition) } - return input._matchAnyNonNewline( + return input.matchAnyNonNewline( at: currentPosition, isScalarSemantics: false) } } @@ -41,7 +47,7 @@ extension Processor { var trips = 0 var extraTrips = payload.extraTrips var savePoint = startQuantifierSavePoint() - + while true { if trips >= payload.minTrips { if extraTrips == 0 { break } diff --git a/Sources/_StringProcessing/Engine/Processor.swift b/Sources/_StringProcessing/Engine/Processor.swift index 3ff767207..0350a37db 100644 --- a/Sources/_StringProcessing/Engine/Processor.swift +++ b/Sources/_StringProcessing/Engine/Processor.swift @@ -35,7 +35,7 @@ struct Processor { /// of the search. `input` can be a "supersequence" of the subject, while /// `input[subjectBounds]` is the logical entity that is being searched. let input: Input - + /// The bounds of the logical subject in `input`. /// /// `subjectBounds` represents the bounds of the string or substring that a @@ -46,7 +46,7 @@ struct Processor { /// `subjectBounds` is always equal to or a subrange of /// `input.startIndex.. - + /// The bounds within the subject for an individual search. /// /// `searchBounds` is equal to `subjectBounds` in some cases, but can be a @@ -62,7 +62,7 @@ struct Processor { let instructions: InstructionList // MARK: Resettable state - + /// The current search position while processing. /// /// `currentPosition` must always be in the range `subjectBounds` or equal @@ -81,7 +81,7 @@ struct Processor { var wordIndexCache: Set? = nil var wordIndexMaxIndex: String.Index? = nil - + var state: State = .inProgress var failureReason: Error? = nil @@ -122,7 +122,7 @@ extension Processor { // Initialize registers with end of search bounds self.registers = Registers(program, searchBounds.upperBound) self.storedCaptures = Array( - repeating: .init(), count: program.registerInfo.captures) + repeating: .init(), count: program.registerInfo.captures) _checkInvariants() } @@ -169,18 +169,12 @@ extension Processor { input[searchBounds] } - // Advance in our input, without any checks or failure signalling - mutating func _uncheckedForcedConsumeOne() { - assert(currentPosition != end) - input.formIndex(after: ¤tPosition) - } - // Advance in our input // // Returns whether the advance succeeded. On failure, our // save point was restored mutating func consume(_ n: Distance) -> Bool { - // TODO: need benchmark coverage + // TODO: needs benchmark coverage guard let idx = input.index( currentPosition, offsetBy: n.rawValue, limitedBy: end ) else { @@ -190,10 +184,10 @@ extension Processor { currentPosition = idx return true } - + // Advances in unicode scalar view mutating func consumeScalar(_ n: Distance) -> Bool { - // TODO: need benchmark coverage + // TODO: needs benchmark coverage guard let idx = input.unicodeScalars.index( currentPosition, offsetBy: n.rawValue, limitedBy: end ) else { @@ -226,11 +220,23 @@ extension Processor { currentPosition < end ? input[currentPosition] : nil } + // MARK: Match functions + // + // TODO: refactor these such that `cycle()` calls the corresponding String + // method directly, and all the step, signalFailure, and + // currentPosition logic is collected into a single place inside + // cycle(). + // Match against the current input element. Returns whether // it succeeded vs signaling an error. - mutating func match(_ e: Element) -> Bool { + mutating func match( + _ e: Element, isCaseInsensitive: Bool + ) -> Bool { guard let next = input.match( - e, at: currentPosition, limitedBy: end + e, + at: currentPosition, + limitedBy: end, + isCaseInsensitive: isCaseInsensitive ) else { signalFailure() return false @@ -239,32 +245,17 @@ extension Processor { return true } - mutating func matchCaseInsensitive(_ e: Element) -> Bool { - // TODO: need benchmark coverage - guard let cur = load(), cur.lowercased() == e.lowercased() else { - signalFailure() - return false - } - _uncheckedForcedConsumeOne() - return true - } - // Match against the current input prefix. Returns whether // it succeeded vs signaling an error. mutating func matchSeq( _ seq: Substring, - isScalarMode: Bool + isScalarSemantics: Bool ) -> Bool { - if isScalarMode { - // TODO: needs benchmark coverage - for s in seq.unicodeScalars { - guard matchScalar(s, boundaryCheck: false) else { return false } - } - return true - } - guard let next = input.matchSeq( - seq, at: currentPosition, limitedBy: end + seq, + at: currentPosition, + limitedBy: end, + isScalarSemantics: isScalarSemantics ) else { signalFailure() return false @@ -274,13 +265,17 @@ extension Processor { return true } - func loadScalar() -> Unicode.Scalar? { - currentPosition < end ? input.unicodeScalars[currentPosition] : nil - } - - mutating func matchScalar(_ s: Unicode.Scalar, boundaryCheck: Bool) -> Bool { + mutating func matchScalar( + _ s: Unicode.Scalar, + boundaryCheck: Bool, + isCaseInsensitive: Bool + ) -> Bool { guard let next = input.matchScalar( - s, at: currentPosition, limitedBy: end, boundaryCheck: boundaryCheck + s, + at: currentPosition, + limitedBy: end, + boundaryCheck: boundaryCheck, + isCaseInsensitive: isCaseInsensitive ) else { signalFailure() return false @@ -289,34 +284,18 @@ extension Processor { return true } - mutating func matchScalarCaseInsensitive( - _ s: Unicode.Scalar, - boundaryCheck: Bool - ) -> Bool { - // TODO: needs benchmark coverage - guard let curScalar = loadScalar(), - s.properties.lowercaseMapping == curScalar.properties.lowercaseMapping, - let idx = input.unicodeScalars.index( - currentPosition, - offsetBy: 1, - limitedBy: end), - (!boundaryCheck || input.isOnGraphemeClusterBoundary(idx)) - else { - signalFailure() - return false - } - currentPosition = idx - return true - } - // If we have a bitset we know that the CharacterClass only matches against // ascii characters, so check if the current input element is ascii then // check if it is set in the bitset mutating func matchBitset( - _ bitset: DSLTree.CustomCharacterClass.AsciiBitset + _ bitset: DSLTree.CustomCharacterClass.AsciiBitset, + isScalarSemantics: Bool ) -> Bool { guard let next = input.matchBitset( - bitset, at: currentPosition, limitedBy: end + bitset, + at: currentPosition, + limitedBy: end, + isScalarSemantics: isScalarSemantics ) else { signalFailure() return false @@ -325,26 +304,11 @@ extension Processor { return true } - // Equivalent of matchBitset but emitted when in unicode scalar semantic mode - mutating func matchBitsetScalar( - _ bitset: DSLTree.CustomCharacterClass.AsciiBitset - ) -> Bool { - // TODO: needs benchmark coverage - guard let curScalar = loadScalar(), - bitset.matches(scalar: curScalar), - let idx = input.unicodeScalars.index(currentPosition, offsetBy: 1, limitedBy: end) else { - signalFailure() - return false - } - currentPosition = idx - return true - } - // Matches the next character/scalar if it is not a newline mutating func matchAnyNonNewline( isScalarSemantics: Bool ) -> Bool { - guard let next = input._matchAnyNonNewline( + guard let next = input.matchAnyNonNewline( at: currentPosition, isScalarSemantics: isScalarSemantics ) else { @@ -425,7 +389,7 @@ extension Processor { // TODO: What should we do here? fatalError("Invalid code: Tried to clear save points when empty") } - + mutating func cycle() { _checkInvariants() assert(state == .inProgress) @@ -519,39 +483,25 @@ extension Processor { } case .match: let (isCaseInsensitive, reg) = payload.elementPayload - if isCaseInsensitive { - if matchCaseInsensitive(registers[reg]) { - controller.step() - } - } else { - if match(registers[reg]) { - controller.step() - } + if match(registers[reg], isCaseInsensitive: isCaseInsensitive) { + controller.step() } case .matchScalar: let (scalar, caseInsensitive, boundaryCheck) = payload.scalarPayload - if caseInsensitive { - if matchScalarCaseInsensitive(scalar, boundaryCheck: boundaryCheck) { - controller.step() - } - } else { - if matchScalar(scalar, boundaryCheck: boundaryCheck) { - controller.step() - } + if matchScalar( + scalar, + boundaryCheck: boundaryCheck, + isCaseInsensitive: caseInsensitive + ) { + controller.step() } case .matchBitset: let (isScalar, reg) = payload.bitsetPayload let bitset = registers[reg] - if isScalar { - if matchBitsetScalar(bitset) { - controller.step() - } - } else { - if matchBitset(bitset) { - controller.step() - } + if matchBitset(bitset, isScalarSemantics: isScalar) { + controller.step() } case .matchBuiltin: @@ -642,7 +592,7 @@ extension Processor { signalFailure() return } - if matchSeq(input[range], isScalarMode: isScalarMode) { + if matchSeq(input[range], isScalarSemantics: isScalarMode) { controller.step() } @@ -688,18 +638,29 @@ extension Processor { } } +// MARK: String matchers +// +// TODO: Refactor into separate file, formalize patterns + extension String { func match( _ char: Character, at pos: Index, - limitedBy end: String.Index + limitedBy end: String.Index, + isCaseInsensitive: Bool ) -> Index? { // TODO: This can be greatly sped up with string internals // TODO: This is also very much quick-check-able assert(end <= endIndex) - guard pos < end, self[pos] == char else { return nil } + guard pos < end else { return nil } + + if isCaseInsensitive { + guard self[pos].lowercased() == char.lowercased() else { return nil } + } else { + guard self[pos] == char else { return nil } + } let idx = index(after: pos) guard idx <= end else { return nil } @@ -710,16 +671,25 @@ extension String { func matchSeq( _ seq: Substring, at pos: Index, - limitedBy end: Index + limitedBy end: Index, + isScalarSemantics: Bool ) -> Index? { // TODO: This can be greatly sped up with string internals // TODO: This is also very much quick-check-able assert(end <= endIndex) var cur = pos - for e in seq { - guard cur < end, self[cur] == e else { return nil } - self.formIndex(after: &cur) + + if isScalarSemantics { + for e in seq.unicodeScalars { + guard cur < end, unicodeScalars[cur] == e else { return nil } + self.unicodeScalars.formIndex(after: &cur) + } + } else { + for e in seq { + guard cur < end, self[cur] == e else { return nil } + self.formIndex(after: &cur) + } } guard cur <= end else { return nil } @@ -730,12 +700,23 @@ extension String { _ scalar: Unicode.Scalar, at pos: Index, limitedBy end: String.Index, - boundaryCheck: Bool + boundaryCheck: Bool, + isCaseInsensitive: Bool ) -> Index? { + // TODO: extremely quick-check-able + // TODO: can be sped up with string internals assert(end <= endIndex) - guard pos < end, unicodeScalars[pos] == scalar else { - return nil + guard pos < end else { return nil } + let curScalar = unicodeScalars[pos] + + if isCaseInsensitive { + guard curScalar.properties.lowercaseMapping == scalar.properties.lowercaseMapping + else { + return nil + } + } else { + guard curScalar == scalar else { return nil } } let idx = unicodeScalars.index(after: pos) @@ -751,20 +732,25 @@ extension String { func matchBitset( _ bitset: DSLTree.CustomCharacterClass.AsciiBitset, at pos: Index, - limitedBy end: Index + limitedBy end: Index, + isScalarSemantics: Bool ) -> Index? { // TODO: extremely quick-check-able // TODO: can be sped up with string internals - assert(end <= endIndex) - guard pos < end, bitset.matches(char: self[pos]) else { - return nil + guard pos < end else { return nil } + + let idx: String.Index + if isScalarSemantics { + guard bitset.matches(unicodeScalars[pos]) else { return nil } + idx = unicodeScalars.index(after: pos) + } else { + guard bitset.matches(self[pos]) else { return nil } + idx = index(after: pos) } - let idx = index(after: pos) guard idx <= end else { return nil } - return idx } diff --git a/Sources/_StringProcessing/Utility/AsciiBitset.swift b/Sources/_StringProcessing/Utility/AsciiBitset.swift index ad3159820..e063447a0 100644 --- a/Sources/_StringProcessing/Utility/AsciiBitset.swift +++ b/Sources/_StringProcessing/Utility/AsciiBitset.swift @@ -57,7 +57,7 @@ extension DSLTree.CustomCharacterClass { } } - internal func matches(char: Character) -> Bool { + internal func matches(_ char: Character) -> Bool { let matched: Bool if let val = char._singleScalarAsciiValue { matched = matches(val) @@ -71,7 +71,7 @@ extension DSLTree.CustomCharacterClass { return matched } - internal func matches(scalar: Unicode.Scalar) -> Bool { + internal func matches(_ scalar: Unicode.Scalar) -> Bool { let matched: Bool if scalar.isASCII { let val = UInt8(ascii: scalar) diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index cdee66ddb..c053b31e4 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -79,7 +79,7 @@ struct _CharacterClassModel: Hashable { let isScalarSemantics = matchLevel == .unicodeScalar - return input._matchBuiltinCC( + return input.matchBuiltinCC( cc, at: currentPosition, isInverted: isInverted, From 035466708c66d202ba3598066c2a220717a8a20f Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Tue, 16 May 2023 12:12:00 -0500 Subject: [PATCH 32/34] Provide unique generic method parameter names (#669) This is getting warned on in the 5.9 compiler, will be an error starting in Swift 6. --- Sources/_RegexParser/Utility/TypeConstruction.swift | 12 ++++++------ Sources/_StringProcessing/Regex/AnyRegexOutput.swift | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Sources/_RegexParser/Utility/TypeConstruction.swift b/Sources/_RegexParser/Utility/TypeConstruction.swift index 4d1765e34..54a7c9263 100644 --- a/Sources/_RegexParser/Utility/TypeConstruction.swift +++ b/Sources/_RegexParser/Utility/TypeConstruction.swift @@ -107,15 +107,15 @@ public enum TypeConstruction { var currentElementAddressUnaligned = UnsafeMutableRawPointer(baseAddress) for element in elements { // Open existential on each element type. - func initializeElement(_ element: T) { + func initializeElement(_ element: U) { currentElementAddressUnaligned = - currentElementAddressUnaligned.roundedUp(toAlignmentOf: T.self) + currentElementAddressUnaligned.roundedUp(toAlignmentOf: U.self) currentElementAddressUnaligned.bindMemory( - to: T.self, capacity: MemoryLayout.size + to: U.self, capacity: MemoryLayout.size ).initialize(to: element) // Advance to the next element (unaligned). currentElementAddressUnaligned = - currentElementAddressUnaligned.advanced(by: MemoryLayout.size) + currentElementAddressUnaligned.advanced(by: MemoryLayout.size) } _openExistential(element, do: initializeElement) } @@ -175,8 +175,8 @@ extension MemoryLayout { if byteOffset == 0 { return 0 } var currentOffset = 0 for (index, type) in elementTypes.enumerated() { - func sizeAndAlignMask(_: T.Type) -> (Int, Int) { - (MemoryLayout.size, MemoryLayout.alignment - 1) + func sizeAndAlignMask(_: U.Type) -> (Int, Int) { + (MemoryLayout.size, MemoryLayout.alignment - 1) } // The ABI of an offset-based key path only stores the byte offset, so // this doesn't work if there's a 0-sized element, e.g. `Void`, diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index 243c1ba01..57bf06dae 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -283,7 +283,7 @@ extension Regex where Output == AnyRegexOutput { /// /// - Parameter regex: A regular expression to convert to use a dynamic /// capture list. - public init(_ regex: Regex) { + public init(_ regex: Regex) { self.init(node: regex.root) } } @@ -299,7 +299,7 @@ extension Regex.Match where Output == AnyRegexOutput { /// /// - Parameter match: A regular expression match to convert to a match with /// type-erased captures. - public init(_ match: Regex.Match) { + public init(_ match: Regex.Match) { self.init( anyRegexOutput: match.anyRegexOutput, range: match.range From 98d5ddc00718d37df83224d9b38786bfeffec69e Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Mon, 22 May 2023 10:36:55 -0600 Subject: [PATCH 33/34] Enable quantification optimizations for scalar semantics (#671) * Quantified scalar semantic matching --- Sources/_StringProcessing/ByteCodeGen.swift | 19 ++++--- .../Engine/Backtracking.swift | 17 ++++++- .../Engine/InstPayload.swift | 49 +++++++++++++------ .../_StringProcessing/Engine/MEBuilder.swift | 20 +++++--- .../_StringProcessing/Engine/MEQuantify.swift | 26 ++++++---- Tests/RegexTests/MatchTests.swift | 44 +++++++++++++++++ 6 files changed, 133 insertions(+), 42 deletions(-) diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index d4c91bd63..00ce0d5f6 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -23,7 +23,9 @@ extension Compiler { var hasEmittedFirstMatchableAtom = false private let compileOptions: _CompileOptions - fileprivate var optimizationsEnabled: Bool { !compileOptions.contains(.disableOptimizations) } + fileprivate var optimizationsEnabled: Bool { + !compileOptions.contains(.disableOptimizations) + } init( options: MatchingOptions, @@ -665,10 +667,10 @@ fileprivate extension Compiler.ByteCodeGen { _ minTrips: Int, _ extraTrips: Int? ) -> Bool { + let isScalarSemantics = options.semanticLevel == .unicodeScalar guard optimizationsEnabled && minTrips <= QuantifyPayload.maxStorableTrips && extraTrips ?? 0 <= QuantifyPayload.maxStorableTrips - && options.semanticLevel == .graphemeCluster && kind != .reluctant else { return false } @@ -678,7 +680,7 @@ fileprivate extension Compiler.ByteCodeGen { guard let bitset = ccc.asAsciiBitset(options) else { return false } - builder.buildQuantify(bitset: bitset, kind, minTrips, extraTrips) + builder.buildQuantify(bitset: bitset, kind, minTrips, extraTrips, isScalarSemantics: isScalarSemantics) case .atom(let atom): switch atom { @@ -687,17 +689,17 @@ fileprivate extension Compiler.ByteCodeGen { guard let val = c._singleScalarAsciiValue else { return false } - builder.buildQuantify(asciiChar: val, kind, minTrips, extraTrips) + builder.buildQuantify(asciiChar: val, kind, minTrips, extraTrips, isScalarSemantics: isScalarSemantics) case .any: builder.buildQuantifyAny( - matchesNewlines: true, kind, minTrips, extraTrips) + matchesNewlines: true, kind, minTrips, extraTrips, isScalarSemantics: isScalarSemantics) case .anyNonNewline: builder.buildQuantifyAny( - matchesNewlines: false, kind, minTrips, extraTrips) + matchesNewlines: false, kind, minTrips, extraTrips, isScalarSemantics: isScalarSemantics) case .dot: builder.buildQuantifyAny( - matchesNewlines: options.dotMatchesNewline, kind, minTrips, extraTrips) + matchesNewlines: options.dotMatchesNewline, kind, minTrips, extraTrips, isScalarSemantics: isScalarSemantics) case .characterClass(let cc): // Custom character class that consumes a single grapheme @@ -706,7 +708,8 @@ fileprivate extension Compiler.ByteCodeGen { model: model, kind, minTrips, - extraTrips) + extraTrips, + isScalarSemantics: isScalarSemantics) default: return false } diff --git a/Sources/_StringProcessing/Engine/Backtracking.swift b/Sources/_StringProcessing/Engine/Backtracking.swift index 3ebb060c9..48470ce91 100644 --- a/Sources/_StringProcessing/Engine/Backtracking.swift +++ b/Sources/_StringProcessing/Engine/Backtracking.swift @@ -16,6 +16,11 @@ extension Processor { // Quantifiers may store a range of positions to restore to var rangeStart: Position? var rangeEnd: Position? + + // FIXME: refactor, for now this field is only used for quantifier save + // points. We should try to separate out the concerns better. + var isScalarSemantics: Bool + // The end of the call stack, so we can slice it off // when failing inside a call. // @@ -68,7 +73,11 @@ extension Processor { rangeStart = nil rangeEnd = nil } else { - input.formIndex(before: &rangeEnd!) + if isScalarSemantics { + input.unicodeScalars.formIndex(before: &rangeEnd!) + } else { + input.formIndex(before: &rangeEnd!) + } } } } @@ -82,19 +91,23 @@ extension Processor { pos: addressOnly ? nil : currentPosition, rangeStart: nil, rangeEnd: nil, + isScalarSemantics: false, // FIXME: refactor away stackEnd: .init(callStack.count), captureEnds: storedCaptures, intRegisters: registers.ints, posRegisters: registers.positions) } - func startQuantifierSavePoint() -> SavePoint { + func startQuantifierSavePoint( + isScalarSemantics: Bool + ) -> SavePoint { // Restores to the instruction AFTER the current quantifier instruction SavePoint( pc: controller.pc + 1, pos: nil, rangeStart: nil, rangeEnd: nil, + isScalarSemantics: isScalarSemantics, stackEnd: .init(callStack.count), captureEnds: storedCaptures, intRegisters: registers.ints, diff --git a/Sources/_StringProcessing/Engine/InstPayload.swift b/Sources/_StringProcessing/Engine/InstPayload.swift index f6d5bfcc7..a0e849851 100644 --- a/Sources/_StringProcessing/Engine/InstPayload.swift +++ b/Sources/_StringProcessing/Engine/InstPayload.swift @@ -370,6 +370,10 @@ extension Instruction.Payload { } } +// TODO: Consider switching all quantification to a quantification +// instruction, where the general path has an instruction list (i.e. a +// slice of a list) + // MARK: Struct definitions struct QuantifyPayload: RawRepresentable { let rawValue: UInt64 @@ -380,9 +384,12 @@ struct QuantifyPayload: RawRepresentable { case builtin = 4 } + // TODO: figure out how to better organize this... + // Future work: optimize this layout -> payload type should be a fast switch // The top 8 bits are reserved for the opcode so we have 56 bits to work with - // b55-b38 - Unused + // b55-b39 - Unused + // b39-b38 - isScalarSemantics // b38-b35 - Payload type (one of 4 types, stored on 3 bits) // b35-b27 - minTrips (8 bit int) // b27-b18 - extraTrips (8 bit value, one bit for nil) @@ -393,6 +400,7 @@ struct QuantifyPayload: RawRepresentable { static var minTripsShift: UInt64 { 27 } static var typeShift: UInt64 { 35 } static var maxStorableTrips: UInt64 { (1 << 8) - 1 } + static var isScalarSemanticsBit: UInt64 { 1 &<< 38 } var quantKindMask: UInt64 { 3 } var extraTripsMask: UInt64 { 0x1FF } @@ -404,7 +412,8 @@ struct QuantifyPayload: RawRepresentable { _ kind: AST.Quantification.Kind, _ minTrips: Int, _ extraTrips: Int?, - _ type: PayloadType + _ type: PayloadType, + isScalarSemantics: Bool ) -> UInt64 { let kindVal: UInt64 switch kind { @@ -415,11 +424,14 @@ struct QuantifyPayload: RawRepresentable { case .possessive: kindVal = 2 } + // TODO: refactor / reimplement let extraTripsVal: UInt64 = extraTrips == nil ? 1 : UInt64(extraTrips!) << 1 - return (kindVal << QuantifyPayload.quantKindShift) + - (extraTripsVal << QuantifyPayload.extraTripsShift) + - (UInt64(minTrips) << QuantifyPayload.minTripsShift) + - (type.rawValue << QuantifyPayload.typeShift) + let scalarSemanticsBit = isScalarSemantics ? Self.isScalarSemanticsBit : 0 + return (kindVal << QuantifyPayload.quantKindShift) | + (extraTripsVal << QuantifyPayload.extraTripsShift) | + (UInt64(minTrips) << QuantifyPayload.minTripsShift) | + (type.rawValue << QuantifyPayload.typeShift) | + scalarSemanticsBit } init(rawValue: UInt64) { @@ -431,46 +443,49 @@ struct QuantifyPayload: RawRepresentable { bitset: AsciiBitsetRegister, _ kind: AST.Quantification.Kind, _ minTrips: Int, - _ extraTrips: Int? + _ extraTrips: Int?, + isScalarSemantics: Bool ) { assert(bitset.bits <= _payloadMask) self.rawValue = bitset.bits - + QuantifyPayload.packInfoValues(kind, minTrips, extraTrips, .bitset) + + QuantifyPayload.packInfoValues(kind, minTrips, extraTrips, .bitset, isScalarSemantics: isScalarSemantics) } init( asciiChar: UInt8, _ kind: AST.Quantification.Kind, _ minTrips: Int, - _ extraTrips: Int? + _ extraTrips: Int?, + isScalarSemantics: Bool ) { self.rawValue = UInt64(asciiChar) - + QuantifyPayload.packInfoValues(kind, minTrips, extraTrips, .asciiChar) + + QuantifyPayload.packInfoValues(kind, minTrips, extraTrips, .asciiChar, isScalarSemantics: isScalarSemantics) } init( matchesNewlines: Bool, _ kind: AST.Quantification.Kind, _ minTrips: Int, - _ extraTrips: Int? + _ extraTrips: Int?, + isScalarSemantics: Bool ) { self.rawValue = (matchesNewlines ? 1 : 0) - + QuantifyPayload.packInfoValues(kind, minTrips, extraTrips, .any) + + QuantifyPayload.packInfoValues(kind, minTrips, extraTrips, .any, isScalarSemantics: isScalarSemantics) } init( model: _CharacterClassModel, _ kind: AST.Quantification.Kind, _ minTrips: Int, - _ extraTrips: Int? + _ extraTrips: Int?, + isScalarSemantics: Bool ) { assert(model.cc.rawValue < 0xFF) - assert(model.matchLevel != .unicodeScalar) let packedModel = model.cc.rawValue + (model.isInverted ? 1 << 9 : 0) + (model.isStrictASCII ? 1 << 10 : 0) self.rawValue = packedModel - + QuantifyPayload.packInfoValues(kind, minTrips, extraTrips, .builtin) + + QuantifyPayload.packInfoValues(kind, minTrips, extraTrips, .builtin, isScalarSemantics: isScalarSemantics) } var type: PayloadType { @@ -500,6 +515,10 @@ struct QuantifyPayload: RawRepresentable { } } + var isScalarSemantics: Bool { + rawValue & Self.isScalarSemanticsBit != 0 + } + var bitset: AsciiBitsetRegister { TypedInt(self.rawValue & payloadMask) } diff --git a/Sources/_StringProcessing/Engine/MEBuilder.swift b/Sources/_StringProcessing/Engine/MEBuilder.swift index 4b623fbda..93801aeec 100644 --- a/Sources/_StringProcessing/Engine/MEBuilder.swift +++ b/Sources/_StringProcessing/Engine/MEBuilder.swift @@ -222,44 +222,48 @@ extension MEProgram.Builder { bitset: DSLTree.CustomCharacterClass.AsciiBitset, _ kind: AST.Quantification.Kind, _ minTrips: Int, - _ extraTrips: Int? + _ extraTrips: Int?, + isScalarSemantics: Bool ) { instructions.append(.init( .quantify, - .init(quantify: .init(bitset: makeAsciiBitset(bitset), kind, minTrips, extraTrips)))) + .init(quantify: .init(bitset: makeAsciiBitset(bitset), kind, minTrips, extraTrips, isScalarSemantics: isScalarSemantics)))) } mutating func buildQuantify( asciiChar: UInt8, _ kind: AST.Quantification.Kind, _ minTrips: Int, - _ extraTrips: Int? + _ extraTrips: Int?, + isScalarSemantics: Bool ) { instructions.append(.init( .quantify, - .init(quantify: .init(asciiChar: asciiChar, kind, minTrips, extraTrips)))) + .init(quantify: .init(asciiChar: asciiChar, kind, minTrips, extraTrips, isScalarSemantics: isScalarSemantics)))) } mutating func buildQuantifyAny( matchesNewlines: Bool, _ kind: AST.Quantification.Kind, _ minTrips: Int, - _ extraTrips: Int? + _ extraTrips: Int?, + isScalarSemantics: Bool ) { instructions.append(.init( .quantify, - .init(quantify: .init(matchesNewlines: matchesNewlines, kind, minTrips, extraTrips)))) + .init(quantify: .init(matchesNewlines: matchesNewlines, kind, minTrips, extraTrips, isScalarSemantics: isScalarSemantics)))) } mutating func buildQuantify( model: _CharacterClassModel, _ kind: AST.Quantification.Kind, _ minTrips: Int, - _ extraTrips: Int? + _ extraTrips: Int?, + isScalarSemantics: Bool ) { instructions.append(.init( .quantify, - .init(quantify: .init(model: model,kind, minTrips, extraTrips)))) + .init(quantify: .init(model: model,kind, minTrips, extraTrips, isScalarSemantics: isScalarSemantics)))) } mutating func buildAccept() { diff --git a/Sources/_StringProcessing/Engine/MEQuantify.swift b/Sources/_StringProcessing/Engine/MEQuantify.swift index 7ca3ae84a..1ff734ccd 100644 --- a/Sources/_StringProcessing/Engine/MEQuantify.swift +++ b/Sources/_StringProcessing/Engine/MEQuantify.swift @@ -1,7 +1,6 @@ extension Processor { func _doQuantifyMatch(_ payload: QuantifyPayload) -> Input.Index? { - // TODO: This optimization is only enabled for grapheme cluster semantics, - // we want these for scalar semantics as well. + let isScalarSemantics = payload.isScalarSemantics switch payload.type { case .bitset: @@ -9,13 +8,13 @@ extension Processor { registers[payload.bitset], at: currentPosition, limitedBy: end, - isScalarSemantics: false) + isScalarSemantics: isScalarSemantics) case .asciiChar: return input.matchScalar( UnicodeScalar.init(_value: UInt32(payload.asciiChar)), at: currentPosition, limitedBy: end, - boundaryCheck: true, + boundaryCheck: !isScalarSemantics, isCaseInsensitive: false) case .builtin: // FIXME: bounds check? endIndex or end? @@ -26,17 +25,20 @@ extension Processor { at: currentPosition, isInverted: payload.builtinIsInverted, isStrictASCII: payload.builtinIsStrict, - isScalarSemantics: false) + isScalarSemantics: isScalarSemantics) case .any: // FIXME: endIndex or end? guard currentPosition < input.endIndex else { return nil } if payload.anyMatchesNewline { + if isScalarSemantics { + return input.unicodeScalars.index(after: currentPosition) + } return input.index(after: currentPosition) } return input.matchAnyNonNewline( - at: currentPosition, isScalarSemantics: false) + at: currentPosition, isScalarSemantics: isScalarSemantics) } } @@ -46,7 +48,9 @@ extension Processor { mutating func runQuantify(_ payload: QuantifyPayload) -> Bool { var trips = 0 var extraTrips = payload.extraTrips - var savePoint = startQuantifierSavePoint() + var savePoint = startQuantifierSavePoint( + isScalarSemantics: payload.isScalarSemantics + ) while true { if trips >= payload.minTrips { @@ -85,7 +89,9 @@ extension Processor { assert(payload.quantKind == .eager && payload.minTrips == 0 && payload.extraTrips == nil) - var savePoint = startQuantifierSavePoint() + var savePoint = startQuantifierSavePoint( + isScalarSemantics: payload.isScalarSemantics + ) while true { savePoint.updateRange(newEnd: currentPosition) @@ -107,7 +113,9 @@ extension Processor { assert(payload.quantKind == .eager && payload.minTrips == 1 && payload.extraTrips == nil) - var savePoint = startQuantifierSavePoint() + var savePoint = startQuantifierSavePoint( + isScalarSemantics: payload.isScalarSemantics + ) while true { let next = _doQuantifyMatch(payload) guard let idx = next else { break } diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index a6c9babbe..3fc547e34 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -620,6 +620,50 @@ extension RegexTests { // TODO: After captures, easier to test these } + func testQuantificationScalarSemantics() { + // TODO: We want more thorough testing here, including "a{n,m}", "a?", etc. + + firstMatchTest("a*", input: "aaa\u{301}", match: "aa") + firstMatchTest("a*", input: "aaa\u{301}", match: "aaa", semanticLevel: .unicodeScalar) + firstMatchTest("a+", input: "aaa\u{301}", match: "aa") + firstMatchTest("a+", input: "aaa\u{301}", match: "aaa", semanticLevel: .unicodeScalar) + firstMatchTest("a?", input: "a\u{301}", match: "") + firstMatchTest("a?", input: "a\u{301}", match: "a", semanticLevel: .unicodeScalar) + + firstMatchTest("[ab]*", input: "abab\u{301}", match: "aba") + firstMatchTest("[ab]*", input: "abab\u{301}", match: "abab", semanticLevel: .unicodeScalar) + firstMatchTest("[ab]+", input: "abab\u{301}", match: "aba") + firstMatchTest("[ab]+", input: "abab\u{301}", match: "abab", semanticLevel: .unicodeScalar) + firstMatchTest("[ab]?", input: "b\u{301}", match: "") + firstMatchTest("[ab]?", input: "b\u{301}", match: "b", semanticLevel: .unicodeScalar) + + firstMatchTest(#"\s*"#, input: " \u{301}", match: " \u{301}") + firstMatchTest(#"\s*"#, input: " \u{301}", match: " ", semanticLevel: .unicodeScalar) + firstMatchTest(#"\s+"#, input: " \u{301}", match: " \u{301}") + firstMatchTest(#"\s+"#, input: " \u{301}", match: " ", semanticLevel: .unicodeScalar) + firstMatchTest(#"\s?"#, input: " \u{301}", match: " \u{301}") + firstMatchTest(#"\s?"#, input: " \u{301}", match: " ", semanticLevel: .unicodeScalar) + + firstMatchTest(#".*?a"#, input: "xxa\u{301}xaZ", match: "xxa\u{301}xa") + firstMatchTest(#".*?a"#, input: "xxa\u{301}xaZ", match: "xxa", semanticLevel: .unicodeScalar) + firstMatchTest(#".+?a"#, input: "xxa\u{301}xaZ", match: "xxa\u{301}xa") + firstMatchTest(#".+?a"#, input: "xxa\u{301}xaZ", match: "xxa", semanticLevel: .unicodeScalar) + firstMatchTest(#".?a"#, input: "e\u{301}aZ", match: "e\u{301}a") + firstMatchTest(#".?a"#, input: "e\u{301}aZ", match: "\u{301}a", semanticLevel: .unicodeScalar) + + firstMatchTest(#".+\u{301}"#, input: "aa\u{301}Z", match: nil) + firstMatchTest(#".+\u{301}"#, input: "aa\u{301}Z", match: "aa\u{301}", semanticLevel: .unicodeScalar) + firstMatchTest(#".*\u{301}"#, input: "\u{301}Z", match: "\u{301}") + firstMatchTest(#".*\u{301}"#, input: "\u{301}Z", match: "\u{301}", semanticLevel: .unicodeScalar) + + firstMatchTest(#".?\u{301}"#, input: "aa\u{302}\u{301}Z", match: nil) + firstMatchTest(#".?\u{301}.?Z"#, input: "aa\u{302}\u{301}Z", match: "\u{302}\u{301}Z", semanticLevel: .unicodeScalar) + firstMatchTest(#".?.?\u{301}.?Z"#, input: "aa\u{302}\u{301}Z", match: "a\u{302}\u{301}Z", semanticLevel: .unicodeScalar) + + + // TODO: other test cases? + } + func testMatchCharacterClasses() { // Must have new stdlib for character class ranges and word boundaries. guard ensureNewStdlib() else { return } From 59fce2ff073e69c03f167b371892de9fe61792bd Mon Sep 17 00:00:00 2001 From: Michael Ilseman Date: Wed, 24 May 2023 07:32:13 -0600 Subject: [PATCH 34/34] Remove redundant test --- Tests/RegexTests/AlgorithmsTests.swift | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Tests/RegexTests/AlgorithmsTests.swift b/Tests/RegexTests/AlgorithmsTests.swift index 0755c1c0e..60548a0a2 100644 --- a/Tests/RegexTests/AlgorithmsTests.swift +++ b/Tests/RegexTests/AlgorithmsTests.swift @@ -185,16 +185,6 @@ class AlgorithmTests: XCTestCase { expectRanges("ADACBADADACBADACB", "ADACB", [0..<5, 7..<12, 12..<17]) } - // rdar://105154010 - func testFirstRangeMissingCrash() { - let str = "%2$@ %#@AROUND_TIME@" - let target = "%@" - XCTAssertNil(str.firstRange(of: target)) - XCTAssertNil(str.dropFirst().dropLast().firstRange(of: target)) - XCTAssertNil(str.dropFirst().dropLast().firstRange(of: target[...])) - XCTAssertNil(str.firstRange(of: target[...])) - } - // rdar://105154010 func testFirstRangeMissingCrash() { let str = "%2$@ %#@AROUND_TIME@"