77
88import Foundation
99
10+ /// Matches and consumes a single element.
1011public struct OneOf : Pattern , RegexConvertible {
1112 @usableFromInline
1213 let group : Group < Input . Element >
@@ -25,33 +26,44 @@ public struct OneOf: Pattern, RegexConvertible {
2526 self . _regex = regex
2627 }
2728
29+ /// Matches any element for which `contains` returns `true`.
30+ /// - Parameters:
31+ /// - description: A descriptive identifier for textual representation of the pattern.
32+ /// - regex: An optional regex matching the same elements.
33+ /// - contains: A closure returning true for any element that matches.
2834 @inlinable
2935 public init ( description: String , regex: String ? = nil , contains: @escaping ( Input . Element ) -> Bool ) {
3036 self . init ( description: description, regex: regex, group: Group ( contains: contains) )
3137 }
3238
39+ /// Matches any elements in `elements`.
40+ /// - Parameter elements: A sequence of elements to match.
3341 @inlinable
34- public init < S: Sequence > ( _ characters : S ) where S. Element == Input . Element {
35- group = Group ( contentsOf: characters )
36- description = #"[" \#( String ( characters ) ) " ]"#
37- _regex = " [ \( NSRegularExpression . escapedPattern ( for: characters . map ( String . init ( describing: ) ) . joined ( ) ) ) ] "
42+ public init < S: Sequence > ( _ elements : S ) where S. Element == Input . Element {
43+ group = Group ( contentsOf: elements )
44+ description = #"[ \#( String ( elements ) ) ]"#
45+ _regex = " [ \( NSRegularExpression . escapedPattern ( for: elements . map ( String . init ( describing: ) ) . joined ( ) ) ) ] "
3846 }
3947
48+ /// Matches any elements _not_ in `elements`.
49+ /// - Parameter elements: A sequence of elements _not_ to match.
4050 @inlinable
41- public init < S: Sequence > ( not characters : S ) where S. Element == Input . Element {
42- group = Group ( contentsOf: characters ) . inverted ( )
43- description = #"[^" \#( String ( characters ) ) " ]"#
44- _regex = " [^ \( NSRegularExpression . escapedPattern ( for: characters . map ( String . init ( describing: ) ) . joined ( ) ) ) ] "
51+ public init < S: Sequence > ( not elements : S ) where S. Element == Input . Element {
52+ group = Group ( contentsOf: elements ) . inverted ( )
53+ description = #"[^ \#( String ( elements ) ) ]"#
54+ _regex = " [^ \( NSRegularExpression . escapedPattern ( for: elements . map ( String . init ( describing: ) ) . joined ( ) ) ) ] "
4555 }
4656
57+ /// Matches any of the provided elements.
4758 @inlinable
4859 public init ( _ oneofs: OneOfConvertible ... ) {
4960 let closures = oneofs. map { $0. contains ( _: ) }
5061 group = Group ( contains: { char in closures. contains ( where: { $0 ( char) } ) } )
51- description = # "[\# ( oneofs. map ( String . init ( describing: ) ) . joined ( separator: " , " ) ) ]"#
62+ description = " [ \( oneofs. map ( String . init ( describing: ) ) . joined ( separator: " , " ) ) ] "
5263 _regex = nil
5364 }
5465
66+ /// Matches anything that is _not_ among the provided elements.
5567 @inlinable
5668 public init ( not oneofs: OneOfConvertible ... ) {
5769 let closures = oneofs. map { $0. contains ( _: ) }
@@ -68,67 +80,80 @@ public struct OneOf: Pattern, RegexConvertible {
6880
6981// MARK: OneOfConvertible
7082
83+ /// A type that `OneOf` can use.
7184public protocol OneOfConvertible {
72- func contains( _: Character ) -> Bool
85+ @inlinable
86+ func contains( _: Pattern . Input . Element ) -> Bool
7387}
7488
7589extension Character : OneOfConvertible {
76- public func contains( _ char: Character ) -> Bool { char == self }
90+ @inlinable
91+ public func contains( _ char: Pattern . Input . Element ) -> Bool { char == self }
7792}
7893
7994extension String : OneOfConvertible { }
8095extension Substring : OneOfConvertible { }
8196
97+ @inlinable
8298public func ... ( lhs: Character, rhs: Character) - > ClosedRange< Character> {
83- precondition ( lhs <= rhs, " The left side of the '...' operator must be less than or equal to the right side " )
99+ precondition ( lhs <= rhs, " The left side of the '...' operator must be less than or equal to the right side. " )
84100 return ClosedRange ( uncheckedBounds: ( lower: lhs, upper: rhs) )
85101}
86102
87103extension ClosedRange : OneOfConvertible where Bound == Character { }
88104
105+ @inlinable
89106public func ..< ( lhs: Character, rhs: Character) - > Range< Character> {
90- precondition ( lhs <= rhs, " The left side of the '..<' operator must be less than or equal to the right side " )
107+ precondition ( lhs <= rhs, " The left side of the '..<' operator must be less than or equal to the right side. " )
91108 return Range ( uncheckedBounds: ( lower: lhs, upper: rhs) )
92109}
93110
94111extension Range : OneOfConvertible where Bound == Character { }
95112
96113extension OneOf : OneOfConvertible {
97- public func contains( _ char: Character ) -> Bool { group. contains ( char) }
114+ @inlinable
115+ public func contains( _ char: Pattern . Input . Element ) -> Bool { group. contains ( char) }
98116}
99117
100118// MARK: Join `&&OneOf • OneOf` into one.
101119
120+ @inlinable
102121public func • ( lhs: AndPattern < OneOf > , rhs: OneOf ) -> OneOf {
103122 OneOf ( description: " \( lhs) \( rhs) " , group: lhs. wrapped. group. intersection ( rhs. group) )
104123}
105124
106- public func • < P: Pattern > ( lhs: AndPattern < OneOf > , rhs: Concat < OneOf , P > ) -> Concat < OneOf , P > {
107- ( lhs • rhs. left) • rhs. right
125+ @inlinable
126+ public func • < P: Pattern > ( lhs: Concat < P , AndPattern < OneOf > > , rhs: OneOf ) -> Concat < P , OneOf > {
127+ lhs. first • ( lhs. second • rhs)
108128}
109129
110130// MARK: Join `!OneOf • Oneof` into one.
111131
132+ @inlinable
112133public func • ( lhs: NotPattern < OneOf > , rhs: OneOf ) -> OneOf {
113134 OneOf ( description: " \( lhs) \( rhs) " , group: rhs. group. subtracting ( lhs. wrapped. group) )
114135}
115136
116- public func • < P: Pattern > ( lhs: NotPattern < OneOf > , rhs: Concat < OneOf , P > ) -> Concat < OneOf , P > {
117- ( lhs • rhs. left) • rhs. right
137+ @inlinable
138+ public func • < P: Pattern > ( lhs: Concat < P , NotPattern < OneOf > > , rhs: OneOf ) -> Concat < P , OneOf > {
139+ lhs. first • ( lhs. second • rhs)
118140}
119141
120142// MARK: Join `OneOf / OneOf` into one.
121143
144+ @inlinable
122145public func / ( lhs: OneOf , rhs: OneOf ) -> OneOf {
123146 OneOf ( description: " \( lhs) / \( rhs) " , group: lhs. group. union ( rhs. group) )
124147}
125148
149+ @inlinable
126150public func / < P: Pattern > ( lhs: OrPattern < P , OneOf > , rhs: OneOf ) -> OrPattern < P , OneOf > {
127151 lhs. first / ( lhs. second / rhs)
128152}
129153
130154// MARK: Common patterns.
131155
156+ /// Succeeds anywhere except for the end of input, and consumes 1 element.
132157public let any = OneOf ( description: " any " , regex: #"[.\p{Zl}]"# ,
133158 contains: { _ in true } )
134159public let alphanumeric = OneOf ( description: " alphanumeric " , regex: #"(?:\p{Alphabetic}|\p{Nd})"# ,
@@ -159,16 +184,20 @@ public let currencySymbol = OneOf(description: "currencySymbol", regex: #"\p{Sc}
159184 contains: { $0. isCurrencySymbol } )
160185
161186extension OneOf {
162- public static let basePatterns : [ OneOf ] = [
163- any, alphanumeric, let ter, lowercase, uppercase, punctuation, whitespace, newline, hexDigit, digit,
187+ /// Predefined OneOf patterns.
188+ public static let patterns : [ OneOf ] = [
189+ alphanumeric, letter, lowercase, uppercase, punctuation, whitespace, newline, hexDigit, digit,
164190 ascii, symbol, mathSymbol, currencySymbol,
165191 ]
166192
167- public static func patterns( for c: Input . Element ) -> [ Pattern ] {
168- OneOf . basePatterns. filter { $0. group. contains ( c) }
193+ /// All the predefined OneOf patterns that match `element`.
194+ public static func patterns( for element: Input . Element ) -> [ OneOf ] {
195+ OneOf . patterns. filter { $0. group. contains ( element) }
169196 }
170197
171- public static func patterns< S: Sequence > ( for s: S ) -> [ Pattern ] where S. Element == Input . Element {
172- OneOf . basePatterns. filter { $0. group. contains ( contentsOf: s) }
198+ /// The predefined OneOf patterns that match _all_ the elements in `sequence`.
199+ public static func patterns< S: Sequence > ( for sequence: S ) -> [ OneOf ] where S. Element == Input . Element {
200+ let sequence = ContiguousArray ( sequence)
201+ return OneOf . patterns. filter { $0. group. contains ( contentsOf: sequence) }
173202 }
174203}
0 commit comments