@@ -151,6 +151,8 @@ struct VariadicsGenerator: ParsableCommand {
151151 print ( " \( kind. rawValue) " , terminator: " " , to: & standardError)
152152 emitQuantifier ( kind: kind, arity: arity)
153153 }
154+ print ( " repeating " , terminator: " " , to: & standardError)
155+ emitRepeating ( arity: arity)
154156 print ( to: & standardError)
155157 }
156158
@@ -307,69 +309,140 @@ struct VariadicsGenerator: ParsableCommand {
307309 }
308310 }
309311 }
312+
313+ struct QuantifierParameters {
314+ var disfavored : String
315+ var genericParams : String
316+ var whereClause : String
317+ var quantifiedCaptures : String
318+ var matchType : String
319+
320+ var repeatingWhereClause : String {
321+ whereClause. isEmpty
322+ ? " where R.Bound == Int "
323+ : whereClause + " , R.Bound == Int "
324+ }
325+
326+ init ( kind: QuantifierKind , arity: Int ) {
327+ self . disfavored = arity == 0 ? " @_disfavoredOverload \n " : " "
328+ self . genericParams = {
329+ var result = " "
330+ if arity > 0 {
331+ result += " W "
332+ result += ( 0 ..< arity) . map { " , C \( $0) " } . joined ( )
333+ result += " , "
334+ }
335+ result += " Component: \( regexProtocolName) "
336+ return result
337+ } ( )
338+
339+ let captures = ( 0 ..< arity) . map { " C \( $0) " }
340+ let capturesJoined = captures. joined ( separator: " , " )
341+ self . whereClause = arity == 0 ? " " :
342+ " where Component.Match == (W, \( capturesJoined) ) "
343+ self . quantifiedCaptures = {
344+ switch kind {
345+ case . zeroOrOne, . zeroOrMore:
346+ return captures. map { " \( $0) ? " } . joined ( separator: " , " )
347+ case . oneOrMore:
348+ return capturesJoined
349+ }
350+ } ( )
351+ self . matchType = arity == 0
352+ ? baseMatchTypeName
353+ : " ( \( baseMatchTypeName) , \( quantifiedCaptures) ) "
354+ }
355+ }
310356
311357 func emitQuantifier( kind: QuantifierKind , arity: Int ) {
312358 assert ( arity >= 0 )
313- let genericParams : String = {
314- var result = " "
315- if arity > 0 {
316- result += " W "
317- result += ( 0 ..< arity) . map { " , C \( $0) " } . joined ( )
318- result += " , "
319- }
320- result += " Component: \( regexProtocolName) "
321- return result
322- } ( )
323- let captures = ( 0 ..< arity) . map { " C \( $0) " }
324- let capturesJoined = captures. joined ( separator: " , " )
325- let whereClause : String = arity == 0 ? " " :
326- " where Component.Match == (W, \( capturesJoined) ) "
327- let quantifiedCaptures : String = {
328- switch kind {
329- case . zeroOrOne, . zeroOrMore:
330- return captures. map { " \( $0) ? " } . joined ( separator: " , " )
331- case . oneOrMore:
332- return capturesJoined
333- }
334- } ( )
335- let matchType = arity == 0 ? baseMatchTypeName : " ( \( baseMatchTypeName) , \( quantifiedCaptures) ) "
359+ let params = QuantifierParameters ( kind: kind, arity: arity)
336360 output ( """
337- \( arity == 0 ? " @_disfavoredOverload " : " " )
338- public func \( kind. rawValue) < \( genericParams) >(
361+ \( params . disfavored ) \
362+ public func \( kind. rawValue) < \( params . genericParams) >(
339363 _ component: Component,
340364 _ behavior: QuantificationBehavior = .eagerly
341- ) -> \( regexTypeName) < \( matchType) > \( whereClause) {
365+ ) -> \( regexTypeName) < \( params . matchType) > \( params . whereClause) {
342366 .init(node: .quantification(. \( kind. astQuantifierAmount) , behavior.astKind, component.regex.root))
343367 }
344368
345- \( arity == 0 ? " @_disfavoredOverload " : " " )
346- public func \( kind. rawValue) < \( genericParams) >(
369+ \( params . disfavored ) \
370+ public func \( kind. rawValue) < \( params . genericParams) >(
347371 _ behavior: QuantificationBehavior = .eagerly,
348372 @RegexBuilder _ component: () -> Component
349- ) -> \( regexTypeName) < \( matchType) > \( whereClause) {
373+ ) -> \( regexTypeName) < \( params . matchType) > \( params . whereClause) {
350374 .init(node: .quantification(. \( kind. astQuantifierAmount) , behavior.astKind, component().regex.root))
351375 }
352376
353- \( arity == 0 ? " @_disfavoredOverload " : " " )
354- public postfix func \( kind. operatorName) < \( genericParams) >(
377+ \( params . disfavored ) \
378+ public postfix func \( kind. operatorName) < \( params . genericParams) >(
355379 _ component: Component
356- ) -> \( regexTypeName) < \( matchType) > \( whereClause) {
380+ ) -> \( regexTypeName) < \( params . matchType) > \( params . whereClause) {
357381 .init(node: .quantification(. \( kind. astQuantifierAmount) , .eager, component.regex.root))
358382 }
359383
360384 \( kind == . zeroOrOne ?
361385 """
362386 extension RegexBuilder {
363- public static func buildLimitedAvailability< \( genericParams) >(
387+ public static func buildLimitedAvailability< \( params . genericParams) >(
364388 _ component: Component
365- ) -> \( regexTypeName) < \( matchType) > \( whereClause) {
389+ ) -> \( regexTypeName) < \( params . matchType) > \( params . whereClause) {
366390 .init(node: .quantification(. \( kind. astQuantifierAmount) , .eager, component.regex.root))
367391 }
368392 }
369393 """ : " " )
370394
371395 """ )
372396 }
397+
398+ func emitRepeating( arity: Int ) {
399+ assert ( arity >= 0 )
400+ // `repeat(..<5)` has the same generic semantics as zeroOrMore
401+ let params = QuantifierParameters ( kind: . zeroOrMore, arity: arity)
402+ // TODO: Could `repeat(count:)` have the same generic semantics as oneOrMore?
403+ // We would need to prohibit `repeat(count: 0)`; can only happen at runtime
404+
405+ output ( """
406+ \( params. disfavored) \
407+ public func repeating< \( params. genericParams) >(
408+ _ component: Component,
409+ count: Int
410+ ) -> \( regexTypeName) < \( params. matchType) > \( params. whereClause) {
411+ assert(count > 0, " Must specify a positive count " )
412+ // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)`
413+ return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root))
414+ }
415+
416+ \( params. disfavored) \
417+ public func repeating< \( params. genericParams) >(
418+ count: Int,
419+ @RegexBuilder _ component: () -> Component
420+ ) -> \( regexTypeName) < \( params. matchType) > \( params. whereClause) {
421+ assert(count > 0, " Must specify a positive count " )
422+ // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)`
423+ return Regex(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root))
424+ }
425+
426+ \( params. disfavored) \
427+ public func repeating< \( params. genericParams) , R: RangeExpression>(
428+ _ component: Component,
429+ _ expression: R,
430+ _ behavior: QuantificationBehavior = .eagerly
431+ ) -> \( regexTypeName) < \( params. matchType) > \( params. repeatingWhereClause) {
432+ .init(node: .repeating(expression.relative(to: 0..<Int.max), behavior, component.regex.root))
433+ }
434+
435+ \( params. disfavored) \
436+ public func repeating< \( params. genericParams) , R: RangeExpression>(
437+ _ expression: R,
438+ _ behavior: QuantificationBehavior = .eagerly,
439+ @RegexBuilder _ component: () -> Component
440+ ) -> \( regexTypeName) < \( params. matchType) > \( params. repeatingWhereClause) {
441+ .init(node: .repeating(expression.relative(to: 0..<Int.max), behavior, component().regex.root))
442+ }
443+
444+ """ )
445+ }
373446
374447 func emitAlternation( leftArity: Int , rightArity: Int ) {
375448 let leftGenParams : String = {
0 commit comments