1010//===----------------------------------------------------------------------===//
1111
1212import _MatchingEngine
13+ @_spi ( RegexBuilder) import _StringProcessing
14+
15+ extension Regex {
16+ public init < Content: RegexComponent > (
17+ @RegexComponentBuilder _ content: ( ) -> Content
18+ ) where Content. Output == Output {
19+ self . init ( content ( ) )
20+ }
21+ }
1322
1423// A convenience protocol for builtin regex components that are initialized with
1524// a `DSLTree` node.
@@ -23,51 +32,6 @@ extension _BuiltinRegexComponent {
2332 }
2433}
2534
26- // MARK: - Primitives
27-
28- extension String : RegexComponent {
29- public typealias Output = Substring
30-
31- public var regex : Regex < Output > {
32- . init( node: . quotedLiteral( self ) )
33- }
34- }
35-
36- extension Substring : RegexComponent {
37- public typealias Output = Substring
38-
39- public var regex : Regex < Output > {
40- . init( node: . quotedLiteral( String ( self ) ) )
41- }
42- }
43-
44- extension Character : RegexComponent {
45- public typealias Output = Substring
46-
47- public var regex : Regex < Output > {
48- . init( node: . atom( . char( self ) ) )
49- }
50- }
51-
52- extension UnicodeScalar : RegexComponent {
53- public typealias Output = Substring
54-
55- public var regex : Regex < Output > {
56- . init( node: . atom( . scalar( self ) ) )
57- }
58- }
59-
60- extension CharacterClass : RegexComponent {
61- public typealias Output = Substring
62-
63- public var regex : Regex < Output > {
64- guard let ast = self . makeAST ( ) else {
65- fatalError ( " FIXME: extended AST? " )
66- }
67- return Regex ( ast: ast)
68- }
69- }
70-
7135// MARK: - Combinators
7236
7337// MARK: Concatenation
@@ -96,9 +60,9 @@ public struct QuantificationBehavior {
9660 case reluctantly
9761 case possessively
9862 }
99-
63+
10064 var kind : Kind
101-
65+
10266 internal var astKind : AST . Quantification . Kind {
10367 switch kind {
10468 case . eagerly: return . eager
@@ -108,19 +72,49 @@ public struct QuantificationBehavior {
10872 }
10973}
11074
75+ extension DSLTree . Node {
76+ /// Generates a DSLTree node for a repeated range of the given DSLTree node.
77+ /// Individual public API functions are in the generated Variadics.swift file.
78+ static func repeating(
79+ _ range: Range < Int > ,
80+ _ behavior: QuantificationBehavior ,
81+ _ node: DSLTree . Node
82+ ) -> DSLTree . Node {
83+ // TODO: Throw these as errors
84+ assert ( range. lowerBound >= 0 , " Cannot specify a negative lower bound " )
85+ assert ( !range. isEmpty, " Cannot specify an empty range " )
86+
87+ switch ( range. lowerBound, range. upperBound) {
88+ case ( 0 , Int . max) : // 0...
89+ return . quantification( . zeroOrMore, behavior. astKind, node)
90+ case ( 1 , Int . max) : // 1...
91+ return . quantification( . oneOrMore, behavior. astKind, node)
92+ case _ where range. count == 1 : // ..<1 or ...0 or any range with count == 1
93+ // Note: `behavior` is ignored in this case
94+ return . quantification( . exactly( . init( faking: range. lowerBound) ) , . eager, node)
95+ case ( 0 , _) : // 0..<n or 0...n or ..<n or ...n
96+ return . quantification( . upToN( . init( faking: range. upperBound) ) , behavior. astKind, node)
97+ case ( _, Int . max) : // n...
98+ return . quantification( . nOrMore( . init( faking: range. lowerBound) ) , behavior. astKind, node)
99+ default : // any other range
100+ return . quantification( . range( . init( faking: range. lowerBound) , . init( faking: range. upperBound) ) , behavior. astKind, node)
101+ }
102+ }
103+ }
104+
111105extension QuantificationBehavior {
112106 /// Match as much of the input string as possible, backtracking when
113107 /// necessary.
114108 public static var eagerly : QuantificationBehavior {
115109 . init( kind: . eagerly)
116110 }
117-
111+
118112 /// Match as little of the input string as possible, expanding the matched
119113 /// region as necessary to complete a match.
120114 public static var reluctantly : QuantificationBehavior {
121115 . init( kind: . reluctantly)
122116 }
123-
117+
124118 /// Match as much of the input string as possible, performing no backtracking.
125119 public static var possessively : QuantificationBehavior {
126120 . init( kind: . possessively)
@@ -247,22 +241,18 @@ public struct TryCapture<Output>: _BuiltinRegexComponent {
247241
248242// MARK: - Backreference
249243
250- struct ReferenceID : Hashable , Equatable {
251- private static var counter : Int = 0
252- var base : Int
253-
254- init ( ) {
255- base = Self . counter
256- Self . counter += 1
257- }
258- }
259-
260244public struct Reference < Capture> : RegexComponent {
261245 let id = ReferenceID ( )
262-
246+
263247 public init ( _ captureType: Capture . Type = Capture . self) { }
264248
265249 public var regex : Regex < Capture > {
266250 . init( node: . atom( . symbolicReference( id) ) )
267251 }
268252}
253+
254+ extension Regex . Match {
255+ public subscript< Capture> ( _ reference: Reference < Capture > ) -> Capture {
256+ self [ reference. id]
257+ }
258+ }
0 commit comments