diff --git a/Package.swift b/Package.swift index e95d98b67..01c6adcb1 100644 --- a/Package.swift +++ b/Package.swift @@ -3,6 +3,13 @@ import PackageDescription +let availabilityDefinition = PackageDescription.SwiftSetting.unsafeFlags([ + "-Xfrontend", + "-define-availability", + "-Xfrontend", + #""SwiftStdlib 5.7:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999""# +]) + let package = Package( name: "swift-experimental-string-processing", products: [ @@ -30,12 +37,14 @@ let package = Package( name: "_RegexParser", dependencies: [], swiftSettings: [ - .unsafeFlags(["-enable-library-evolution"]) + .unsafeFlags(["-enable-library-evolution"]), + availabilityDefinition ]), .testTarget( name: "MatchingEngineTests", dependencies: [ - "_RegexParser", "_StringProcessing"]), + "_RegexParser", "_StringProcessing" + ]), .target( name: "_CUnicode", dependencies: []), @@ -44,26 +53,31 @@ let package = Package( dependencies: ["_RegexParser", "_CUnicode"], swiftSettings: [ .unsafeFlags(["-enable-library-evolution"]), + availabilityDefinition ]), .target( name: "RegexBuilder", dependencies: ["_StringProcessing", "_RegexParser"], swiftSettings: [ .unsafeFlags(["-enable-library-evolution"]), - .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]) + .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), + availabilityDefinition ]), .testTarget( name: "RegexTests", - dependencies: ["_StringProcessing"]), + dependencies: ["_StringProcessing"], + swiftSettings: [availabilityDefinition]), .testTarget( name: "RegexBuilderTests", dependencies: ["_StringProcessing", "RegexBuilder"], swiftSettings: [ - .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]) + .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), + availabilityDefinition ]), .target( name: "Prototypes", - dependencies: ["_RegexParser", "_StringProcessing"]), + dependencies: ["_RegexParser", "_StringProcessing"], + swiftSettings: [availabilityDefinition]), // MARK: Scripts .executableTarget( @@ -84,11 +98,12 @@ let package = Package( name: "Exercises", dependencies: ["_RegexParser", "Prototypes", "_StringProcessing", "RegexBuilder"], swiftSettings: [ - .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]) + .unsafeFlags(["-Xfrontend", "-enable-experimental-pairwise-build-block"]), + availabilityDefinition ]), .testTarget( name: "ExercisesTests", - dependencies: ["Exercises"]), + dependencies: ["Exercises"], + swiftSettings: [availabilityDefinition]), ] ) - diff --git a/Sources/RegexBuilder/Anchor.swift b/Sources/RegexBuilder/Anchor.swift index ba910bd30..7933b987a 100644 --- a/Sources/RegexBuilder/Anchor.swift +++ b/Sources/RegexBuilder/Anchor.swift @@ -12,6 +12,7 @@ import _RegexParser @_spi(RegexBuilder) import _StringProcessing +@available(SwiftStdlib 5.7, *) public struct Anchor { internal enum Kind { case startOfSubject @@ -107,6 +108,7 @@ extension Anchor { } } +@available(SwiftStdlib 5.7, *) public struct Lookahead: _BuiltinRegexComponent { public var regex: Regex diff --git a/Sources/RegexBuilder/Builder.swift b/Sources/RegexBuilder/Builder.swift index 8921c8f25..be9a48e36 100644 --- a/Sources/RegexBuilder/Builder.swift +++ b/Sources/RegexBuilder/Builder.swift @@ -11,6 +11,7 @@ @_spi(RegexBuilder) import _StringProcessing +@available(SwiftStdlib 5.7, *) @resultBuilder public enum RegexComponentBuilder { public static func buildBlock() -> Regex { diff --git a/Sources/RegexBuilder/CharacterClass.swift b/Sources/RegexBuilder/CharacterClass.swift index 78ebd49a2..99e981d33 100644 --- a/Sources/RegexBuilder/CharacterClass.swift +++ b/Sources/RegexBuilder/CharacterClass.swift @@ -12,6 +12,7 @@ import _RegexParser @_spi(RegexBuilder) import _StringProcessing +@available(SwiftStdlib 5.7, *) public struct CharacterClass { internal var ccc: DSLTree.CustomCharacterClass @@ -122,6 +123,7 @@ extension CharacterClass { } /// Range syntax for characters in `CharacterClass`es. +@available(SwiftStdlib 5.7, *) public func ...(lhs: Character, rhs: Character) -> CharacterClass { let range: DSLTree.CustomCharacterClass.Member = .range(.char(lhs), .char(rhs)) let ccc = DSLTree.CustomCharacterClass(members: [range], isInverted: false) @@ -130,6 +132,7 @@ public func ...(lhs: Character, rhs: Character) -> CharacterClass { /// Range syntax for unicode scalars in `CharacterClass`es. @_disfavoredOverload +@available(SwiftStdlib 5.7, *) public func ...(lhs: UnicodeScalar, rhs: UnicodeScalar) -> CharacterClass { let range: DSLTree.CustomCharacterClass.Member = .range(.scalar(lhs), .scalar(rhs)) let ccc = DSLTree.CustomCharacterClass(members: [range], isInverted: false) diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 80662be41..717e172b0 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -54,6 +54,7 @@ extension _BuiltinRegexComponent { // Note: Quantifiers are currently gyb'd. /// Specifies how much to attempt to match when using a quantifier. +@available(SwiftStdlib 5.7, *) public struct QuantificationBehavior { internal enum Kind { case eagerly @@ -121,6 +122,7 @@ extension QuantificationBehavior { } } +@available(SwiftStdlib 5.7, *) public struct OneOrMore: _BuiltinRegexComponent { public var regex: Regex @@ -132,6 +134,7 @@ public struct OneOrMore: _BuiltinRegexComponent { // Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct ZeroOrMore: _BuiltinRegexComponent { public var regex: Regex @@ -143,6 +146,7 @@ public struct ZeroOrMore: _BuiltinRegexComponent { // Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct Optionally: _BuiltinRegexComponent { public var regex: Regex @@ -154,6 +158,7 @@ public struct Optionally: _BuiltinRegexComponent { // Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct Repeat: _BuiltinRegexComponent { public var regex: Regex @@ -179,6 +184,7 @@ public struct Repeat: _BuiltinRegexComponent { // ) -> R where R.Match == (W, C...) // } +@available(SwiftStdlib 5.7, *) @resultBuilder public struct AlternationBuilder { @_disfavoredOverload @@ -201,6 +207,7 @@ public struct AlternationBuilder { } } +@available(SwiftStdlib 5.7, *) public struct ChoiceOf: _BuiltinRegexComponent { public var regex: Regex @@ -215,6 +222,7 @@ public struct ChoiceOf: _BuiltinRegexComponent { // MARK: - Capture +@available(SwiftStdlib 5.7, *) public struct Capture: _BuiltinRegexComponent { public var regex: Regex @@ -225,6 +233,7 @@ public struct Capture: _BuiltinRegexComponent { // Note: Public initializers are currently gyb'd. See Variadics.swift. } +@available(SwiftStdlib 5.7, *) public struct TryCapture: _BuiltinRegexComponent { public var regex: Regex @@ -239,6 +248,7 @@ public struct TryCapture: _BuiltinRegexComponent { /// An atomic group, i.e. 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 @@ -249,6 +259,7 @@ public struct Local: _BuiltinRegexComponent { // MARK: - Backreference +@available(SwiftStdlib 5.7, *) public struct Reference: RegexComponent { let id = ReferenceID() diff --git a/Sources/RegexBuilder/Match.swift b/Sources/RegexBuilder/Match.swift index e6718d96b..32dc889d9 100644 --- a/Sources/RegexBuilder/Match.swift +++ b/Sources/RegexBuilder/Match.swift @@ -12,12 +12,14 @@ import _StringProcessing extension String { + @available(SwiftStdlib 5.7, *) public func wholeMatch( @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { wholeMatch(of: content()) } + @available(SwiftStdlib 5.7, *) public func prefixMatch( @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { @@ -26,12 +28,14 @@ extension String { } extension Substring { + @available(SwiftStdlib 5.7, *) public func wholeMatch( @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { wholeMatch(of: content()) } + @available(SwiftStdlib 5.7, *) public func prefixMatch( @RegexComponentBuilder of content: () -> R ) -> Regex.Match? { diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift index 46568192f..2f38095d8 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Contains.swift @@ -27,6 +27,7 @@ extension Collection where Element: Equatable { /// - Parameter other: A sequence to search for within this collection. /// - Returns: `true` if the collection contains the specified sequence, /// otherwise `false`. + @available(SwiftStdlib 5.7, *) public func contains(_ other: S) -> Bool where S.Element == Element { @@ -50,6 +51,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: A regex to search for within this collection. /// - Returns: `true` if the regex was found in the collection, otherwise /// `false`. + @available(SwiftStdlib 5.7, *) public func contains(_ regex: R) -> Bool { contains(RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift index 405fe47ef..e75cdbdc4 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/FirstRange.swift @@ -37,6 +37,7 @@ extension Collection where Element: Equatable { /// - Parameter sequence: The sequence to search for. /// - Returns: A range in the collection of the first occurrence of `sequence`. /// Returns nil if `sequence` is not found. + @available(SwiftStdlib 5.7, *) public func firstRange( of sequence: S ) -> Range? where S.Element == Element { @@ -52,6 +53,7 @@ extension BidirectionalCollection where Element: Comparable { /// - Parameter other: The sequence to search for. /// - Returns: A range in the collection of the first occurrence of `sequence`. /// Returns `nil` if `sequence` is not found. + @available(SwiftStdlib 5.7, *) public func firstRange( of other: S ) -> Range? where S.Element == Element { @@ -71,6 +73,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: The regex to search for. /// - Returns: A range in the collection of the first occurrence of `regex`. /// Returns `nil` if `regex` is not found. + @available(SwiftStdlib 5.7, *) public func firstRange(of regex: R) -> Range? { firstRange(of: RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift index bc23a284c..4a6da6c10 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Replace.swift @@ -77,6 +77,7 @@ extension RangeReplaceableCollection where Element: Equatable { /// to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of `other` in /// `subrange` of the collection are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ other: S, with replacement: Replacement, @@ -99,6 +100,7 @@ extension RangeReplaceableCollection where Element: Equatable { /// to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of `other` in /// `subrange` of the collection are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ other: S, with replacement: Replacement, @@ -117,6 +119,7 @@ extension RangeReplaceableCollection where Element: Equatable { /// - replacement: The new elements to add to the collection. /// - maxReplacements: A number specifying how many occurrences of `other` /// to replace. Default is `Int.max`. + @available(SwiftStdlib 5.7, *) public mutating func replace( _ other: S, with replacement: Replacement, @@ -184,6 +187,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// sequence matching `regex` to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` in `subrange` are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, with replacement: Replacement, @@ -206,6 +210,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// sequence matching `regex` to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, with replacement: Replacement, @@ -225,6 +230,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// - replacement: The new elements to add to the collection. /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. + @available(SwiftStdlib 5.7, *) public mutating func replace( _ regex: R, with replacement: Replacement, diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift index 346094f9e..01572fe49 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/StartsWith.swift @@ -53,6 +53,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter regex: A regex to compare to this sequence. /// - Returns: `true` if the initial elements of the sequence matches the /// beginning of `regex`; otherwise, `false`. + @available(SwiftStdlib 5.7, *) public func starts(with regex: R) -> Bool { starts(with: RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift index ed7cd7bc4..fd0dbefdb 100644 --- a/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift +++ b/Sources/_StringProcessing/Algorithms/Algorithms/Trim.swift @@ -111,6 +111,7 @@ extension Collection { } extension Collection where SubSequence == Self { + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix( while predicate: @escaping (Element) -> Bool ) { @@ -121,6 +122,7 @@ extension Collection where SubSequence == Self { extension RangeReplaceableCollection { @_disfavoredOverload + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix( while predicate: @escaping (Element) -> Bool ) { @@ -185,6 +187,7 @@ extension Collection where Element: Equatable { /// element should be removed from the collection. /// - Returns: A collection containing the elements of the collection that are /// not removed by `predicate`. + @available(SwiftStdlib 5.7, *) public func trimmingPrefix( _ prefix: Prefix ) -> SubSequence where Prefix.Element == Element { @@ -198,6 +201,7 @@ extension Collection where SubSequence == Self, Element: Equatable { /// - Parameter predicate: A closure that takes an element of the sequence /// as its argument and returns a Boolean value indicating whether the /// element should be removed from the collection. + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix( _ prefix: Prefix ) where Prefix.Element == Element { @@ -212,6 +216,7 @@ extension RangeReplaceableCollection where Element: Equatable { /// - Parameter predicate: A closure that takes an element of the sequence /// as its argument and returns a Boolean value indicating whether the /// element should be removed from the collection. + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix( _ prefix: Prefix ) where Prefix.Element == Element { @@ -279,6 +284,7 @@ extension BidirectionalCollection where SubSequence == Substring { /// - Parameter prefix: The collection to remove from this collection. /// - Returns: A collection containing the elements that does not match /// `prefix` from the start. + @available(SwiftStdlib 5.7, *) public func trimmingPrefix(_ regex: R) -> SubSequence { trimmingPrefix(RegexConsumer(regex)) } @@ -297,6 +303,7 @@ extension RangeReplaceableCollection { /// Removes the initial elements that matches the given regex. /// - Parameter regex: The regex to remove from this collection. + @available(SwiftStdlib 5.7, *) public mutating func trimPrefix(_ regex: R) { trimPrefix(RegexConsumer(regex)) } diff --git a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift index 74ab48839..82ca00797 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift @@ -122,6 +122,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// sequence matching `regex` to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, with replacement: (Regex.Match) throws -> Replacement, @@ -157,6 +158,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// sequence matching `regex` to replace. Default is `Int.max`. /// - Returns: A new collection in which all occurrences of subsequence /// matching `regex` are replaced by `replacement`. + @available(SwiftStdlib 5.7, *) public func replacing( _ regex: R, with replacement: (Regex.Match) throws -> Replacement, @@ -177,6 +179,7 @@ extension RangeReplaceableCollection where SubSequence == Substring { /// including captures, and returns a replacement collection. /// - maxReplacements: A number specifying how many occurrences of the /// sequence matching `regex` to replace. Default is `Int.max`. + @available(SwiftStdlib 5.7, *) public mutating func replace( _ regex: R, with replacement: (Regex.Match) throws -> Replacement, diff --git a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift index bd0fc47c9..ea9659faf 100644 --- a/Sources/_StringProcessing/Regex/AnyRegexOutput.swift +++ b/Sources/_StringProcessing/Regex/AnyRegexOutput.swift @@ -38,6 +38,7 @@ extension Regex.Match where Output == AnyRegexOutput { } /// A type-erased regex output +@available(SwiftStdlib 5.7, *) public struct AnyRegexOutput { let input: String fileprivate let _elements: [ElementRepresentation] diff --git a/Sources/_StringProcessing/Regex/Core.swift b/Sources/_StringProcessing/Regex/Core.swift index 96d0f3a68..b77ee7ece 100644 --- a/Sources/_StringProcessing/Regex/Core.swift +++ b/Sources/_StringProcessing/Regex/Core.swift @@ -13,6 +13,7 @@ import _RegexParser /// A type that represents a regular expression. +@available(SwiftStdlib 5.7, *) public protocol RegexComponent { associatedtype Output var regex: Regex { get } @@ -25,6 +26,7 @@ public protocol RegexComponent { /// print(match.0) // "axb" /// print(match.1) // "x" /// +@available(SwiftStdlib 5.7, *) public struct Regex: RegexComponent { let program: Program diff --git a/Sources/_StringProcessing/Regex/DSLConsumers.swift b/Sources/_StringProcessing/Regex/DSLConsumers.swift index 8d64f8355..8bca244c2 100644 --- a/Sources/_StringProcessing/Regex/DSLConsumers.swift +++ b/Sources/_StringProcessing/Regex/DSLConsumers.swift @@ -9,6 +9,7 @@ // //===----------------------------------------------------------------------===// +@available(SwiftStdlib 5.7, *) public protocol CustomRegexComponent: RegexComponent { func match( _ input: String, diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index f37505cb4..6ae4804e5 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -12,6 +12,7 @@ import _RegexParser @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public struct DSLTree { var root: Node var options: Options? @@ -162,6 +163,7 @@ extension DSLTree { // CollectionConsumer @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public typealias _ConsumerInterface = ( String, Range ) throws -> String.Index? @@ -169,12 +171,14 @@ public typealias _ConsumerInterface = ( // Type producing consume // TODO: better name @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public typealias _MatcherInterface = ( String, String.Index, Range ) throws -> (String.Index, Any)? // Character-set (post grapheme segmentation) @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public typealias _CharacterPredicateInterface = ( (Character) -> Bool ) @@ -375,6 +379,7 @@ extension DSLTree.Node { } @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public struct ReferenceID: Hashable, Equatable { private static var counter: Int = 0 var base: Int @@ -386,6 +391,7 @@ public struct ReferenceID: Hashable, Equatable { } @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public struct CaptureTransform: Hashable, CustomStringConvertible { public enum Closure { case failable((Substring) throws -> Any?) diff --git a/Sources/_StringProcessing/_CharacterClassModel.swift b/Sources/_StringProcessing/_CharacterClassModel.swift index e184689f1..0c45d2b6c 100644 --- a/Sources/_StringProcessing/_CharacterClassModel.swift +++ b/Sources/_StringProcessing/_CharacterClassModel.swift @@ -16,6 +16,7 @@ import _RegexParser // of parsing or to store in an AST @_spi(RegexBuilder) +@available(SwiftStdlib 5.7, *) public struct _CharacterClassModel: Hashable { /// The actual character class to match. var cc: Representation diff --git a/Tests/RegexBuilderTests/AlgorithmsTests.swift b/Tests/RegexBuilderTests/AlgorithmsTests.swift index 7625af385..fed584ff7 100644 --- a/Tests/RegexBuilderTests/AlgorithmsTests.swift +++ b/Tests/RegexBuilderTests/AlgorithmsTests.swift @@ -13,6 +13,7 @@ import XCTest import _StringProcessing @testable import RegexBuilder +@available(SwiftStdlib 5.7, *) class RegexConsumerTests: XCTestCase { // FIXME: enable this test when we update the return type of `matches(of:)` // when SE-0346 is available