diff --git a/Sources/RegexBuilder/Variadics.swift b/Sources/RegexBuilder/Variadics.swift index e367a2ecb..c1e380144 100644 --- a/Sources/RegexBuilder/Variadics.swift +++ b/Sources/RegexBuilder/Variadics.swift @@ -784,7 +784,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == Substring { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -795,7 +795,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == Substring { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } @@ -913,7 +913,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -923,7 +923,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } @@ -1039,7 +1039,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -1049,7 +1049,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } @@ -1165,7 +1165,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -1175,7 +1175,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } @@ -1291,7 +1291,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -1301,7 +1301,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } @@ -1417,7 +1417,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -1427,7 +1427,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } @@ -1543,7 +1543,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -1553,7 +1553,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } @@ -1669,7 +1669,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -1679,7 +1679,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } @@ -1795,7 +1795,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -1805,7 +1805,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } @@ -1921,7 +1921,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -1931,7 +1931,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } @@ -2047,7 +2047,7 @@ extension Repeat { _ component: Component, count: Int ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -2057,7 +2057,7 @@ extension Repeat { count: Int, @RegexComponentBuilder _ component: () -> Component ) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?, C10?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } diff --git a/Sources/VariadicsGenerator/VariadicsGenerator.swift b/Sources/VariadicsGenerator/VariadicsGenerator.swift index 98885f6f2..faab75762 100644 --- a/Sources/VariadicsGenerator/VariadicsGenerator.swift +++ b/Sources/VariadicsGenerator/VariadicsGenerator.swift @@ -505,7 +505,7 @@ struct VariadicsGenerator: ParsableCommand { _ component: Component, count: Int ) \(params.whereClauseForInit) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component)) } @@ -516,7 +516,7 @@ struct VariadicsGenerator: ParsableCommand { count: Int, @\(concatBuilderName) _ component: () -> Component ) \(params.whereClauseForInit) { - assert(count > 0, "Must specify a positive count") + precondition(count >= 0, "Must specify a positive count") let factory = makeFactory() self.init(factory.exactly(count, component())) } diff --git a/Sources/_StringProcessing/Regex/DSLTree.swift b/Sources/_StringProcessing/Regex/DSLTree.swift index 196927803..0714c5d2c 100644 --- a/Sources/_StringProcessing/Regex/DSLTree.swift +++ b/Sources/_StringProcessing/Regex/DSLTree.swift @@ -853,25 +853,38 @@ extension DSLTree.Node { _ 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.dslTreeKind) } ?? .default - - switch (range.lowerBound, range.upperBound) { - case (0, Int.max): // 0... - return .quantification(.zeroOrMore, kind, node) - case (1, Int.max): // 1... - return .quantification(.oneOrMore, kind, node) - case _ where range.count == 1: // ..<1 or ...0 or any range with count == 1 + precondition(range.lowerBound >= 0, "Cannot specify a negative lower bound") + precondition(!range.isEmpty, "Cannot specify an empty range") + + let kind: DSLTree.QuantificationKind = behavior + .map { .explicit($0.dslTreeKind) } ?? .default + + // The upper bound needs adjusting down as + // `.quantification` expects a closed range. + let lower = range.lowerBound + let upperInclusive = range.upperBound - 1 + + // Unbounded cases + if range.upperBound == Int.max { + switch lower { + case 0: // 0... + return .quantification(.zeroOrMore, kind, node) + case 1: // 1... + return .quantification(.oneOrMore, kind, node) + default: // n... + return .quantification(.nOrMore(lower), kind, node) + } + } + if range.count == 1 { + // ..<1 or ...0 or any range with count == 1 // Note: `behavior` is ignored in this case - return .quantification(.exactly(range.lowerBound), .default, node) - case (0, _): // 0.. = Regex { let charClass = CharacterClass(.digit, "a"..."h")//.ignoringCase() Capture {