Skip to content

Commit 0ec8b08

Browse files
authored
Merge pull request #557 from hamishknight/main-merge
2 parents bbd1b54 + da2500e commit 0ec8b08

26 files changed

+761
-390
lines changed

Sources/RegexBuilder/CharacterClass.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,10 @@ extension RegexComponent where Self == CharacterClass {
4848
.init(DSLTree.CustomCharacterClass(members: [.atom(.any)]))
4949
}
5050

51-
public static var anyGrapheme: CharacterClass {
51+
public static var anyGraphemeCluster: CharacterClass {
5252
.init(unconverted: .anyGrapheme)
5353
}
5454

55-
public static var anyUnicodeScalar: CharacterClass {
56-
.init(unconverted: .anyUnicodeScalar)
57-
}
58-
5955
public static var whitespace: CharacterClass {
6056
.init(unconverted: .whitespace)
6157
}

Sources/RegexBuilder/Variadics.swift

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ extension Repeat {
784784
_ component: Component,
785785
count: Int
786786
) where RegexOutput == Substring {
787-
assert(count > 0, "Must specify a positive count")
787+
precondition(count >= 0, "Must specify a positive count")
788788
let factory = makeFactory()
789789
self.init(factory.exactly(count, component))
790790
}
@@ -795,7 +795,7 @@ extension Repeat {
795795
count: Int,
796796
@RegexComponentBuilder _ component: () -> Component
797797
) where RegexOutput == Substring {
798-
assert(count > 0, "Must specify a positive count")
798+
precondition(count >= 0, "Must specify a positive count")
799799
let factory = makeFactory()
800800
self.init(factory.exactly(count, component()))
801801
}
@@ -913,7 +913,7 @@ extension Repeat {
913913
_ component: Component,
914914
count: Int
915915
) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) {
916-
assert(count > 0, "Must specify a positive count")
916+
precondition(count >= 0, "Must specify a positive count")
917917
let factory = makeFactory()
918918
self.init(factory.exactly(count, component))
919919
}
@@ -923,7 +923,7 @@ extension Repeat {
923923
count: Int,
924924
@RegexComponentBuilder _ component: () -> Component
925925
) where RegexOutput == (Substring, C1?), Component.RegexOutput == (W, C1) {
926-
assert(count > 0, "Must specify a positive count")
926+
precondition(count >= 0, "Must specify a positive count")
927927
let factory = makeFactory()
928928
self.init(factory.exactly(count, component()))
929929
}
@@ -1039,7 +1039,7 @@ extension Repeat {
10391039
_ component: Component,
10401040
count: Int
10411041
) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) {
1042-
assert(count > 0, "Must specify a positive count")
1042+
precondition(count >= 0, "Must specify a positive count")
10431043
let factory = makeFactory()
10441044
self.init(factory.exactly(count, component))
10451045
}
@@ -1049,7 +1049,7 @@ extension Repeat {
10491049
count: Int,
10501050
@RegexComponentBuilder _ component: () -> Component
10511051
) where RegexOutput == (Substring, C1?, C2?), Component.RegexOutput == (W, C1, C2) {
1052-
assert(count > 0, "Must specify a positive count")
1052+
precondition(count >= 0, "Must specify a positive count")
10531053
let factory = makeFactory()
10541054
self.init(factory.exactly(count, component()))
10551055
}
@@ -1165,7 +1165,7 @@ extension Repeat {
11651165
_ component: Component,
11661166
count: Int
11671167
) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) {
1168-
assert(count > 0, "Must specify a positive count")
1168+
precondition(count >= 0, "Must specify a positive count")
11691169
let factory = makeFactory()
11701170
self.init(factory.exactly(count, component))
11711171
}
@@ -1175,7 +1175,7 @@ extension Repeat {
11751175
count: Int,
11761176
@RegexComponentBuilder _ component: () -> Component
11771177
) where RegexOutput == (Substring, C1?, C2?, C3?), Component.RegexOutput == (W, C1, C2, C3) {
1178-
assert(count > 0, "Must specify a positive count")
1178+
precondition(count >= 0, "Must specify a positive count")
11791179
let factory = makeFactory()
11801180
self.init(factory.exactly(count, component()))
11811181
}
@@ -1291,7 +1291,7 @@ extension Repeat {
12911291
_ component: Component,
12921292
count: Int
12931293
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) {
1294-
assert(count > 0, "Must specify a positive count")
1294+
precondition(count >= 0, "Must specify a positive count")
12951295
let factory = makeFactory()
12961296
self.init(factory.exactly(count, component))
12971297
}
@@ -1301,7 +1301,7 @@ extension Repeat {
13011301
count: Int,
13021302
@RegexComponentBuilder _ component: () -> Component
13031303
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?), Component.RegexOutput == (W, C1, C2, C3, C4) {
1304-
assert(count > 0, "Must specify a positive count")
1304+
precondition(count >= 0, "Must specify a positive count")
13051305
let factory = makeFactory()
13061306
self.init(factory.exactly(count, component()))
13071307
}
@@ -1417,7 +1417,7 @@ extension Repeat {
14171417
_ component: Component,
14181418
count: Int
14191419
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) {
1420-
assert(count > 0, "Must specify a positive count")
1420+
precondition(count >= 0, "Must specify a positive count")
14211421
let factory = makeFactory()
14221422
self.init(factory.exactly(count, component))
14231423
}
@@ -1427,7 +1427,7 @@ extension Repeat {
14271427
count: Int,
14281428
@RegexComponentBuilder _ component: () -> Component
14291429
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?), Component.RegexOutput == (W, C1, C2, C3, C4, C5) {
1430-
assert(count > 0, "Must specify a positive count")
1430+
precondition(count >= 0, "Must specify a positive count")
14311431
let factory = makeFactory()
14321432
self.init(factory.exactly(count, component()))
14331433
}
@@ -1543,7 +1543,7 @@ extension Repeat {
15431543
_ component: Component,
15441544
count: Int
15451545
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) {
1546-
assert(count > 0, "Must specify a positive count")
1546+
precondition(count >= 0, "Must specify a positive count")
15471547
let factory = makeFactory()
15481548
self.init(factory.exactly(count, component))
15491549
}
@@ -1553,7 +1553,7 @@ extension Repeat {
15531553
count: Int,
15541554
@RegexComponentBuilder _ component: () -> Component
15551555
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6) {
1556-
assert(count > 0, "Must specify a positive count")
1556+
precondition(count >= 0, "Must specify a positive count")
15571557
let factory = makeFactory()
15581558
self.init(factory.exactly(count, component()))
15591559
}
@@ -1669,7 +1669,7 @@ extension Repeat {
16691669
_ component: Component,
16701670
count: Int
16711671
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) {
1672-
assert(count > 0, "Must specify a positive count")
1672+
precondition(count >= 0, "Must specify a positive count")
16731673
let factory = makeFactory()
16741674
self.init(factory.exactly(count, component))
16751675
}
@@ -1679,7 +1679,7 @@ extension Repeat {
16791679
count: Int,
16801680
@RegexComponentBuilder _ component: () -> Component
16811681
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7) {
1682-
assert(count > 0, "Must specify a positive count")
1682+
precondition(count >= 0, "Must specify a positive count")
16831683
let factory = makeFactory()
16841684
self.init(factory.exactly(count, component()))
16851685
}
@@ -1795,7 +1795,7 @@ extension Repeat {
17951795
_ component: Component,
17961796
count: Int
17971797
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) {
1798-
assert(count > 0, "Must specify a positive count")
1798+
precondition(count >= 0, "Must specify a positive count")
17991799
let factory = makeFactory()
18001800
self.init(factory.exactly(count, component))
18011801
}
@@ -1805,7 +1805,7 @@ extension Repeat {
18051805
count: Int,
18061806
@RegexComponentBuilder _ component: () -> Component
18071807
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8) {
1808-
assert(count > 0, "Must specify a positive count")
1808+
precondition(count >= 0, "Must specify a positive count")
18091809
let factory = makeFactory()
18101810
self.init(factory.exactly(count, component()))
18111811
}
@@ -1921,7 +1921,7 @@ extension Repeat {
19211921
_ component: Component,
19221922
count: Int
19231923
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) {
1924-
assert(count > 0, "Must specify a positive count")
1924+
precondition(count >= 0, "Must specify a positive count")
19251925
let factory = makeFactory()
19261926
self.init(factory.exactly(count, component))
19271927
}
@@ -1931,7 +1931,7 @@ extension Repeat {
19311931
count: Int,
19321932
@RegexComponentBuilder _ component: () -> Component
19331933
) where RegexOutput == (Substring, C1?, C2?, C3?, C4?, C5?, C6?, C7?, C8?, C9?), Component.RegexOutput == (W, C1, C2, C3, C4, C5, C6, C7, C8, C9) {
1934-
assert(count > 0, "Must specify a positive count")
1934+
precondition(count >= 0, "Must specify a positive count")
19351935
let factory = makeFactory()
19361936
self.init(factory.exactly(count, component()))
19371937
}
@@ -2047,7 +2047,7 @@ extension Repeat {
20472047
_ component: Component,
20482048
count: Int
20492049
) 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) {
2050-
assert(count > 0, "Must specify a positive count")
2050+
precondition(count >= 0, "Must specify a positive count")
20512051
let factory = makeFactory()
20522052
self.init(factory.exactly(count, component))
20532053
}
@@ -2057,7 +2057,7 @@ extension Repeat {
20572057
count: Int,
20582058
@RegexComponentBuilder _ component: () -> Component
20592059
) 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) {
2060-
assert(count > 0, "Must specify a positive count")
2060+
precondition(count >= 0, "Must specify a positive count")
20612061
let factory = makeFactory()
20622062
self.init(factory.exactly(count, component()))
20632063
}

Sources/VariadicsGenerator/VariadicsGenerator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ struct VariadicsGenerator: ParsableCommand {
505505
_ component: Component,
506506
count: Int
507507
) \(params.whereClauseForInit) {
508-
assert(count > 0, "Must specify a positive count")
508+
precondition(count >= 0, "Must specify a positive count")
509509
let factory = makeFactory()
510510
self.init(factory.exactly(count, component))
511511
}
@@ -516,7 +516,7 @@ struct VariadicsGenerator: ParsableCommand {
516516
count: Int,
517517
@\(concatBuilderName) _ component: () -> Component
518518
) \(params.whereClauseForInit) {
519-
assert(count > 0, "Must specify a positive count")
519+
precondition(count >= 0, "Must specify a positive count")
520520
let factory = makeFactory()
521521
self.init(factory.exactly(count, component()))
522522
}

Sources/_RegexParser/Regex/Parse/CaptureList.swift

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -57,63 +57,105 @@ extension CaptureList {
5757
}
5858
}
5959

60+
extension CaptureList {
61+
public struct Builder {
62+
public var captures = CaptureList()
63+
64+
public init() {}
65+
66+
public struct OptionalNesting {
67+
// We maintain two depths, inner and outer. These allow e.g the nesting
68+
// of a regex literal in a DSL, where outside of the scope of the literal,
69+
// nesting is allowed, but inside the literal at most one extra layer of
70+
// optionality may be added.
71+
public var outerDepth: Int
72+
public var canNest: Bool
73+
public var innerDepth: Int
74+
75+
internal init(outerDepth: Int, canNest: Bool) {
76+
self.outerDepth = outerDepth
77+
self.canNest = canNest
78+
self.innerDepth = 0
79+
}
80+
81+
public init(canNest: Bool) {
82+
self.init(outerDepth: 0, canNest: canNest)
83+
}
84+
85+
public var depth: Int { outerDepth + innerDepth }
86+
87+
public var disablingNesting: Self {
88+
// If we are currently able to nest, store the current depth as the
89+
// outer depth, and disable nesting for an inner scope.
90+
guard canNest else { return self }
91+
return .init(outerDepth: depth, canNest: false)
92+
}
93+
94+
public var addingOptional: Self {
95+
var result = self
96+
result.innerDepth = canNest ? innerDepth + 1 : 1
97+
return result
98+
}
99+
}
100+
}
101+
}
102+
60103
// MARK: Generating from AST
61104

62-
extension AST.Node {
63-
public func _addCaptures(
64-
to list: inout CaptureList,
65-
optionalNesting nesting: Int
105+
extension CaptureList.Builder {
106+
public mutating func addCaptures(
107+
of node: AST.Node, optionalNesting nesting: OptionalNesting
66108
) {
67-
let addOptional = nesting+1
68-
switch self {
109+
switch node {
69110
case let .alternation(a):
70111
for child in a.children {
71-
child._addCaptures(to: &list, optionalNesting: addOptional)
112+
addCaptures(of: child, optionalNesting: nesting.addingOptional)
72113
}
73114

74115
case let .concatenation(c):
75116
for child in c.children {
76-
child._addCaptures(to: &list, optionalNesting: nesting)
117+
addCaptures(of: child, optionalNesting: nesting)
77118
}
78119

79120
case let .group(g):
80121
switch g.kind.value {
81122
case .capture:
82-
list.append(.init(optionalDepth: nesting, g.location))
123+
captures.append(.init(optionalDepth: nesting.depth, g.location))
83124

84125
case .namedCapture(let name):
85-
list.append(.init(name: name.value, optionalDepth: nesting, g.location))
126+
captures.append(.init(
127+
name: name.value, optionalDepth: nesting.depth, g.location))
86128

87129
case .balancedCapture(let b):
88-
list.append(.init(name: b.name?.value, optionalDepth: nesting,
89-
g.location))
130+
captures.append(.init(
131+
name: b.name?.value, optionalDepth: nesting.depth, g.location))
90132

91133
default: break
92134
}
93-
g.child._addCaptures(to: &list, optionalNesting: nesting)
135+
addCaptures(of: g.child, optionalNesting: nesting)
94136

95137
case .conditional(let c):
96138
switch c.condition.kind {
97139
case .group(let g):
98-
AST.Node.group(g)._addCaptures(to: &list, optionalNesting: nesting)
140+
addCaptures(of: .group(g), optionalNesting: nesting)
99141
default:
100142
break
101143
}
102144

103-
c.trueBranch._addCaptures(to: &list, optionalNesting: addOptional)
104-
c.falseBranch._addCaptures(to: &list, optionalNesting: addOptional)
145+
addCaptures(of: c.trueBranch, optionalNesting: nesting.addingOptional)
146+
addCaptures(of: c.falseBranch, optionalNesting: nesting.addingOptional)
105147

106148
case .quantification(let q):
107149
var optNesting = nesting
108150
if q.amount.value.bounds.atLeast == 0 {
109-
optNesting += 1
151+
optNesting = optNesting.addingOptional
110152
}
111-
q.child._addCaptures(to: &list, optionalNesting: optNesting)
153+
addCaptures(of: q.child, optionalNesting: optNesting)
112154

113155
case .absentFunction(let abs):
114156
switch abs.kind {
115157
case .expression(_, _, let child):
116-
child._addCaptures(to: &list, optionalNesting: nesting)
158+
addCaptures(of: child, optionalNesting: nesting)
117159
case .clearer, .repeater, .stopper:
118160
break
119161
}
@@ -122,16 +164,17 @@ extension AST.Node {
122164
break
123165
}
124166
}
167+
public static func build(_ ast: AST) -> CaptureList {
168+
var builder = Self()
169+
builder.captures.append(.init(optionalDepth: 0, .fake))
170+
builder.addCaptures(of: ast.root, optionalNesting: .init(canNest: false))
171+
return builder.captures
172+
}
125173
}
126174

127175
extension AST {
128176
/// The capture list (including the whole match) of this AST.
129-
public var captureList: CaptureList {
130-
var caps = CaptureList()
131-
caps.append(.init(optionalDepth: 0, .fake))
132-
root._addCaptures(to: &caps, optionalNesting: 0)
133-
return caps
134-
}
177+
public var captureList: CaptureList { .Builder.build(self) }
135178
}
136179

137180
// MARK: Convenience for testing and inspection

0 commit comments

Comments
 (0)