From e04f2fc01f52fc897b9e140a1e6d3ef0e5bd996e Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Thu, 14 Apr 2022 17:15:47 -0500 Subject: [PATCH] RegexBuilder quantifiers take an optional behavior --- Sources/RegexBuilder/DSL.swift | 16 +- Sources/RegexBuilder/Variadics.swift | 440 ++++++++++-------- .../VariadicsGenerator.swift | 20 +- Sources/_StringProcessing/ByteCodeGen.swift | 18 +- .../_StringProcessing/PrintAsPattern.swift | 11 + .../Regex/ASTConversion.swift | 2 +- Sources/_StringProcessing/Regex/DSLTree.swift | 12 +- Sources/_StringProcessing/Regex/Options.swift | 58 ++- Tests/RegexBuilderTests/RegexDSLTests.swift | 20 +- 9 files changed, 355 insertions(+), 242 deletions(-) diff --git a/Sources/RegexBuilder/DSL.swift b/Sources/RegexBuilder/DSL.swift index 80662be41..1edf03922 100644 --- a/Sources/RegexBuilder/DSL.swift +++ b/Sources/RegexBuilder/DSL.swift @@ -77,27 +77,29 @@ extension DSLTree.Node { /// Individual public API functions are in the generated Variadics.swift file. static func repeating( _ range: Range, - _ behavior: QuantificationBehavior, + _ behavior: QuantificationBehavior?, _ node: DSLTree.Node ) -> DSLTree.Node { // TODO: Throw these as errors assert(range.lowerBound >= 0, "Cannot specify a negative lower bound") assert(!range.isEmpty, "Cannot specify an empty range") + + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default switch (range.lowerBound, range.upperBound) { case (0, Int.max): // 0... - return .quantification(.zeroOrMore, behavior.astKind, node) + return .quantification(.zeroOrMore, kind, node) case (1, Int.max): // 1... - return .quantification(.oneOrMore, behavior.astKind, node) + return .quantification(.oneOrMore, kind, node) case _ where range.count == 1: // ..<1 or ...0 or any range with count == 1 // Note: `behavior` is ignored in this case - return .quantification(.exactly(.init(faking: range.lowerBound)), .eager, node) + return .quantification(.exactly(.init(faking: range.lowerBound)), .default, node) case (0, _): // 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == Substring { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { @_disfavoredOverload public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == Substring { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -502,26 +504,28 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { @_disfavoredOverload public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == Substring { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { @_disfavoredOverload public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == Substring { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -530,19 +534,21 @@ extension OneOrMore { @_disfavoredOverload public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == Substring { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { @_disfavoredOverload public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == Substring { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -555,7 +561,7 @@ extension Repeat { ) where Output == Substring { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } @_disfavoredOverload @@ -565,14 +571,14 @@ extension Repeat { ) where Output == Substring { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } @_disfavoredOverload public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == Substring, R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == Substring, R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?), Component.Output == (W, C0) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?), Component.Output == (W, C0) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -608,24 +616,26 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?)> where Component.Output == (W, C0) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?), Component.Output == (W, C0) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?), Component.Output == (W, C0) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -633,18 +643,20 @@ extension ZeroOrMore { extension OneOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0), Component.Output == (W, C0) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0), Component.Output == (W, C0) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -656,7 +668,7 @@ extension Repeat { ) where Output == (Substring, C0?), Component.Output == (W, C0) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } public init( @@ -665,20 +677,20 @@ extension Repeat { ) where Output == (Substring, C0?), Component.Output == (W, C0) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?), Component.Output == (W, C0), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?), Component.Output == (W, C0), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -706,24 +720,26 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?)> where Component.Output == (W, C0, C1) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -731,18 +747,20 @@ extension ZeroOrMore { extension OneOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0, C1), Component.Output == (W, C0, C1) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -754,7 +772,7 @@ extension Repeat { ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } public init( @@ -763,20 +781,20 @@ extension Repeat { ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?), Component.Output == (W, C0, C1), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -804,24 +824,26 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?)> where Component.Output == (W, C0, C1, C2) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -829,18 +851,20 @@ extension ZeroOrMore { extension OneOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0, C1, C2), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0, C1, C2), Component.Output == (W, C0, C1, C2) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -852,7 +876,7 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } public init( @@ -861,20 +885,20 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?), Component.Output == (W, C0, C1, C2), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -902,24 +928,26 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?)> where Component.Output == (W, C0, C1, C2, C3) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -927,18 +955,20 @@ extension ZeroOrMore { extension OneOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0, C1, C2, C3), Component.Output == (W, C0, C1, C2, C3) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -950,7 +980,7 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } public init( @@ -959,20 +989,20 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?), Component.Output == (W, C0, C1, C2, C3), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1000,24 +1032,26 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?)> where Component.Output == (W, C0, C1, C2, C3, C4) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1025,18 +1059,20 @@ extension ZeroOrMore { extension OneOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0, C1, C2, C3, C4), Component.Output == (W, C0, C1, C2, C3, C4) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1048,7 +1084,7 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } public init( @@ -1057,20 +1093,20 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?), Component.Output == (W, C0, C1, C2, C3, C4), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1098,24 +1136,26 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1123,18 +1163,20 @@ extension ZeroOrMore { extension OneOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0, C1, C2, C3, C4, C5), Component.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0, C1, C2, C3, C4, C5), Component.Output == (W, C0, C1, C2, C3, C4, C5) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1146,7 +1188,7 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } public init( @@ -1155,20 +1197,20 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?), Component.Output == (W, C0, C1, C2, C3, C4, C5), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1196,24 +1240,26 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1221,18 +1267,20 @@ extension ZeroOrMore { extension OneOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1244,7 +1292,7 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } public init( @@ -1253,20 +1301,20 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1294,24 +1344,26 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1319,18 +1371,20 @@ extension ZeroOrMore { extension OneOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1342,7 +1396,7 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } public init( @@ -1351,20 +1405,20 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1392,24 +1448,26 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1417,18 +1475,20 @@ extension ZeroOrMore { extension OneOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1440,7 +1500,7 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } public init( @@ -1449,20 +1509,20 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component.regex.root)) } } extension Optionally { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.zeroOrOne, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrOne, kind, component().regex.root)) } } @@ -1490,24 +1552,26 @@ extension RegexComponentBuilder { public static func buildLimitedAvailability( _ component: Component ) -> Regex<(Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?)> where Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - .init(node: .quantification(.zeroOrOne, .eager, component.regex.root)) + .init(node: .quantification(.zeroOrOne, .default, component.regex.root)) } } extension ZeroOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component.regex.root)) } } extension ZeroOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.zeroOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.zeroOrMore, kind, component().regex.root)) } } @@ -1515,18 +1579,20 @@ extension ZeroOrMore { extension OneOrMore { public init( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component.regex.root)) } } extension OneOrMore { public init( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - self.init(node: .quantification(.oneOrMore, behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.oneOrMore, kind, component().regex.root)) } } @@ -1538,7 +1604,7 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } public init( @@ -1547,20 +1613,20 @@ extension Repeat { ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } public init( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @RegexComponentBuilder _ component: () -> Component ) where Output == (Substring, C0?, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.Output == (W, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9), R.Bound == Int { self.init(node: .repeating(expression.relative(to: 0..( _ component: Component, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) \(params.whereClauseForInit) { - self.init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component.regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.\(kind.astQuantifierAmount), kind, component.regex.root)) } } extension \(kind.rawValue) { \(params.disfavored)\ public init<\(params.genericParams)>( - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @\(concatBuilderName) _ component: () -> Component ) \(params.whereClauseForInit) { - self.init(node: .quantification(.\(kind.astQuantifierAmount), behavior.astKind, component().regex.root)) + let kind: DSLTree.QuantificationKind = behavior.map { .explicit($0.astKind) } ?? .default + self.init(node: .quantification(.\(kind.astQuantifierAmount), kind, component().regex.root)) } } @@ -393,7 +395,7 @@ struct VariadicsGenerator: ParsableCommand { public static func buildLimitedAvailability<\(params.genericParams)>( _ component: Component ) -> \(regexTypeName)<\(params.matchType)> \(params.whereClause) { - .init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component.regex.root)) + .init(node: .quantification(.\(kind.astQuantifierAmount), .default, component.regex.root)) } } """ : "") @@ -471,7 +473,7 @@ struct VariadicsGenerator: ParsableCommand { ) \(params.whereClauseForInit) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component.regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component.regex.root)) } \(params.disfavored)\ @@ -481,14 +483,14 @@ struct VariadicsGenerator: ParsableCommand { ) \(params.whereClauseForInit) { assert(count > 0, "Must specify a positive count") // TODO: Emit a warning about `repeatMatch(count: 0)` or `repeatMatch(count: 1)` - self.init(node: .quantification(.exactly(.init(faking: count)), .eager, component().regex.root)) + self.init(node: .quantification(.exactly(.init(faking: count)), .default, component().regex.root)) } \(params.disfavored)\ public init<\(params.genericParams), R: RangeExpression>( _ component: Component, _ expression: R, - _ behavior: QuantificationBehavior = .eagerly + _ behavior: QuantificationBehavior? = nil ) \(params.repeatingWhereClause) { self.init(node: .repeating(expression.relative(to: 0..( _ expression: R, - _ behavior: QuantificationBehavior = .eagerly, + _ behavior: QuantificationBehavior? = nil, @\(concatBuilderName) _ component: () -> Component ) \(params.repeatingWhereClause) { self.init(node: .repeating(expression.relative(to: 0.. Regex { + wrapInOption(.multiline, addingIf: matchLineEndings) + } + + /// Returns a regular expression where quantifiers are reluctant by default + /// instead of eager. + /// + /// This method corresponds to applying the `U` option in a regular + /// expression literal. + /// + /// - Parameter useReluctantQuantifiers: A Boolean value indicating whether + /// quantifiers should be reluctant by default. + public func reluctantQuantifiers(_ useReluctantQuantifiers: Bool = true) -> Regex { + wrapInOption(.reluctantByDefault, addingIf: useReluctantQuantifiers) + } + /// Returns a regular expression that matches with the specified semantic /// level. /// @@ -126,38 +152,6 @@ public struct RegexSemanticLevel: Hashable { } } -// Options that only affect literals -extension RegexComponent { - /// Returns a regular expression where the start and end of input - /// anchors (`^` and `$`) also match against the start and end of a line. - /// - /// This method corresponds to applying the `m` option in a regular - /// expression literal, and only applies to regular expressions specified as - /// literals. For this behavior in the `RegexBuilder` syntax, see - /// ``Anchor.startOfLine``, ``Anchor.endOfLine``, ``Anchor.startOfInput``, - /// and ``Anchor.endOfInput``. - /// - /// - Parameter matchLineEndings: A Boolean value indicating whether `^` and - /// `$` should match the start and end of lines, respectively. - public func anchorsMatchLineEndings(_ matchLineEndings: Bool = true) -> Regex { - wrapInOption(.multiline, addingIf: matchLineEndings) - } - - /// Returns a regular expression where quantifiers are reluctant by default - /// instead of eager. - /// - /// This method corresponds to applying the `U` option in a regular - /// expression literal, and only applies to regular expressions specified as - /// literals. In the `RegexBuilder` syntax, pass a ``QuantificationBehavior`` - /// value to any quantification method to change its behavior. - /// - /// - Parameter useReluctantCaptures: A Boolean value indicating whether - /// quantifiers should be reluctant by default. - public func reluctantCaptures(_ useReluctantCaptures: Bool = true) -> Regex { - wrapInOption(.reluctantByDefault, addingIf: useReluctantCaptures) - } -} - // MARK: - Helper method extension RegexComponent { fileprivate func wrapInOption( diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 0c0bf7c8f..e80990ee1 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -262,6 +262,24 @@ class RegexDSLTests: XCTestCase { } .ignoringCase(false) } + + try _testDSLCaptures( + ("abcdef123", ("abcdef123", "a", "123")), + matchType: (Substring, Substring, Substring).self, ==) { + Capture { + // Reluctant behavior due to option + OneOrMore(.anyOf("abcd")) + .reluctantQuantifiers() + } + ZeroOrMore("a"..."z") + + Capture { + // Eager behavior due to explicit parameter, despite option + OneOrMore(.digit, .eagerly) + .reluctantQuantifiers() + } + ZeroOrMore(.digit) + } } func testQuantificationBehavior() throws { @@ -293,7 +311,7 @@ class RegexDSLTests: XCTestCase { OneOrMore(.word) Capture(.digit) ZeroOrMore(.any) - }.reluctantCaptures() + }.reluctantQuantifiers() } } #endif