Skip to content

Commit eccd21b

Browse files
committed
Parameterize determining capture structure
1 parent 022380f commit eccd21b

File tree

5 files changed

+150
-78
lines changed

5 files changed

+150
-78
lines changed

Sources/_MatchingEngine/Regex/AST/AST.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ extension AST {
2626
public var hasCapture: Bool { root.hasCapture }
2727

2828
/// The capture structure of this AST tree.
29-
public var captureStructure: CaptureStructure { root.captureStructure }
29+
public var captureStructure: CaptureStructure {
30+
var constructor = CaptureStructure.Constructor(.flatten)
31+
return root._captureStructure(&constructor)
32+
}
3033
}
3134

3235
extension AST {

Sources/_MatchingEngine/Regex/Parse/CaptureStructure.swift

Lines changed: 86 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -25,137 +25,161 @@ public enum CaptureStructure: Equatable {
2525
}
2626
}
2727

28+
// TODO: Below are all flattening constructors. Instead create
29+
// a builder/visitor that can store the structuralization
30+
// approach
31+
2832
extension CaptureStructure {
29-
public init<C: Collection>(
30-
alternating children: C
31-
) where C.Element: _TreeNode {
33+
public struct Constructor {
34+
var strategy: Strategy
35+
36+
public init(_ strategy: Strategy = .flatten) {
37+
guard strategy == .flatten else {
38+
fatalError("TODO: adjust creator methods")
39+
}
40+
self.strategy = strategy
41+
}
42+
}
43+
}
44+
45+
extension CaptureStructure.Constructor {
46+
public mutating func alternating<C: Collection>(
47+
_ children: C
48+
) -> CaptureStructure where C.Element: _TreeNode {
3249
assert(children.count > 1)
33-
self = children
34-
.map(\.captureStructure)
35-
.reduce(.empty, +)
36-
.map(CaptureStructure.optional)
50+
return children.map {
51+
$0._captureStructure(&self)
52+
}.reduce(.empty, +)
53+
.map(CaptureStructure.optional)
3754
}
38-
public init<C: Collection>(
39-
concatenating children: C
40-
) where C.Element: _TreeNode {
41-
self = children.map(\.captureStructure).reduce(.empty, +)
55+
public mutating func concatenating<C: Collection>(
56+
_ children: C
57+
) -> CaptureStructure where C.Element: _TreeNode {
58+
return children.map {
59+
$0._captureStructure(&self)
60+
}.reduce(.empty, +)
4261
}
4362

44-
public init<T: _TreeNode>(
45-
grouping child: T, as kind: AST.Group.Kind
46-
) {
47-
let innerCaptures = child.captureStructure
63+
public mutating func grouping<T: _TreeNode>(
64+
_ child: T, as kind: AST.Group.Kind
65+
) -> CaptureStructure {
66+
let innerCaptures = child._captureStructure(&self)
4867
switch kind {
4968
case .capture:
50-
self = .atom() + innerCaptures
69+
return .atom() + innerCaptures
5170
case .namedCapture(let name):
52-
self = .atom(name: name.value) + innerCaptures
71+
return .atom(name: name.value) + innerCaptures
5372
case .balancedCapture(let b):
54-
self = .atom(name: b.name?.value) + innerCaptures
73+
return .atom(name: b.name?.value) + innerCaptures
5574
default:
5675
precondition(!kind.isCapturing)
57-
self = innerCaptures
76+
return innerCaptures
5877
}
5978
}
6079

61-
public init<T: _TreeNode>(
62-
grouping child: T,
80+
public mutating func grouping<T: _TreeNode>(
81+
_ child: T,
6382
as kind: AST.Group.Kind,
6483
withTransform transform: CaptureTransform
65-
) {
66-
let innerCaptures = child.captureStructure
84+
) -> CaptureStructure {
85+
let innerCaptures = child._captureStructure(&self)
6786
switch kind {
6887
case .capture:
69-
self = .atom(type: AnyType(transform.resultType)) + innerCaptures
88+
return .atom(type: AnyType(transform.resultType)) + innerCaptures
7089
case .namedCapture(let name):
71-
self = .atom(name: name.value, type: AnyType(transform.resultType))
90+
return .atom(name: name.value, type: AnyType(transform.resultType))
7291
+ innerCaptures
7392
default:
74-
self = innerCaptures
93+
return innerCaptures
7594
}
7695
}
7796

7897
// TODO: We'll likely want/need a generalization of
7998
// conditional's condition kind.
80-
public init<T: _TreeNode>(
81-
condition: AST.Conditional.Condition.Kind,
99+
public mutating func condition<T: _TreeNode>(
100+
_ condition: AST.Conditional.Condition.Kind,
82101
trueBranch: T,
83102
falseBranch: T
84-
) {
103+
) -> CaptureStructure {
85104
// A conditional's capture structure is effectively that of an alternation
86105
// between the true and false branches. However the condition may also
87106
// have captures in the case of a group condition.
88107
var captures = CaptureStructure.empty
89108
switch condition {
90109
case .group(let g):
91-
captures = captures + AST.Node.group(g).captureStructure
110+
captures = captures + AST.Node.group(g)._captureStructure(&self)
92111
default:
93112
break
94113
}
95-
let branchCaptures = trueBranch.captureStructure +
96-
falseBranch.captureStructure
97-
self = captures + branchCaptures.map(
114+
let branchCaptures = trueBranch._captureStructure(&self) +
115+
falseBranch._captureStructure(&self)
116+
return captures + branchCaptures.map(
98117
CaptureStructure.optional)
99118
}
100119

101-
public init<T: _TreeNode>(
102-
quantifying child: T, amount: AST.Quantification.Amount
103-
) {
104-
self = child.captureStructure.map(
120+
public mutating func quantifying<T: _TreeNode>(
121+
_ child: T, amount: AST.Quantification.Amount
122+
) -> CaptureStructure {
123+
return child._captureStructure(&self).map(
105124
amount == .zeroOrOne
106125
? CaptureStructure.optional
107126
: CaptureStructure.array)
108127
}
109128

110129
// TODO: Will need to adjust for DSLTree support, and
111130
// "absent" isn't the best name for these.
112-
public init(
113-
absent kind: AST.AbsentFunction.Kind
114-
) {
131+
public mutating func absent(
132+
_ kind: AST.AbsentFunction.Kind
133+
) -> CaptureStructure {
115134
// Only the child of an expression absent function is relevant, as the
116135
// other expressions don't actually get matched against.
117136
switch kind {
118137
case .expression(_, _, let child):
119-
self = child.captureStructure
138+
return child._captureStructure(&self)
120139
case .clearer, .repeater, .stopper:
121-
self = .empty
140+
return .empty
122141
}
123142
}
124143

125144
}
126145

127146
extension AST.Node {
128-
public var captureStructure: CaptureStructure {
147+
public func _captureStructure(
148+
_ constructor: inout CaptureStructure.Constructor
149+
) -> CaptureStructure {
150+
guard constructor.strategy == .flatten else {
151+
fatalError("TODO")
152+
}
153+
129154
// Note: This implementation could be more optimized.
130155
switch self {
131156
case let .alternation(a):
132-
return CaptureStructure(alternating: a.children)
157+
return constructor.alternating(a.children)
133158

134159
case let .concatenation(c):
135-
return CaptureStructure(concatenating: c.children)
160+
return constructor.concatenating(c.children)
136161

137162
case let .group(g):
138-
return CaptureStructure(
139-
grouping: g.child, as: g.kind.value)
163+
return constructor.grouping(g.child, as: g.kind.value)
140164

141165
case .groupTransform(let g, let transform):
142-
return CaptureStructure(
143-
grouping: g.child,
166+
return constructor.grouping(
167+
g.child,
144168
as: g.kind.value,
145169
withTransform: transform)
146170

147171
case .conditional(let c):
148-
return CaptureStructure(
149-
condition: c.condition.kind,
172+
return constructor.condition(
173+
c.condition.kind,
150174
trueBranch: c.trueBranch,
151175
falseBranch: c.falseBranch)
152176

153177
case .quantification(let q):
154-
return CaptureStructure(
155-
quantifying: q.child, amount: q.amount.value)
178+
return constructor.quantifying(
179+
q.child, amount: q.amount.value)
156180

157181
case .absentFunction(let abs):
158-
return CaptureStructure(absent: abs.kind)
182+
return constructor.absent(abs.kind)
159183

160184
case .quote, .trivia, .atom, .customCharacterClass, .empty:
161185
return .empty
@@ -436,3 +460,11 @@ extension CaptureStructure: CustomStringConvertible {
436460
}
437461
}
438462
}
463+
464+
extension CaptureStructure.Constructor {
465+
public enum Strategy {
466+
case flatten
467+
case nest
468+
// case drop(after: Int)...
469+
}
470+
}

Sources/_MatchingEngine/Regex/TreeProtocols.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
public protocol _TreeNode {
44
var children: [Self]? { get }
55

6-
var captureStructure: CaptureStructure { get }
6+
func _captureStructure(
7+
_: inout CaptureStructure.Constructor
8+
) -> CaptureStructure
79
}
810

911
extension _TreeNode {

Sources/_StringProcessing/Legacy/LegacyCompile.swift

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ func compile(
108108
instructions.append(.goto(label: start.label!))
109109
instructions.append(done)
110110
if childHasCaptures {
111-
instructions.append(.captureArray(childType: child.captureStructure.type))
111+
var constructor = CaptureStructure.Constructor(
112+
.flatten)
113+
let type = child._captureStructure(&constructor).type
114+
instructions.append(.captureArray(childType: type))
112115
instructions.append(.endGroup)
113116
}
114117
return
@@ -131,7 +134,10 @@ func compile(
131134
instructions.append(.goto(label: start.label!))
132135
instructions.append(done)
133136
if childHasCaptures {
134-
instructions.append(.captureArray(childType: child.captureStructure.type))
137+
var constructor = CaptureStructure.Constructor(
138+
.flatten)
139+
let type = child._captureStructure(&constructor).type
140+
instructions.append(.captureArray(childType: type))
135141
instructions.append(.endGroup)
136142
}
137143
return
@@ -144,11 +150,16 @@ func compile(
144150
let done = createLabel()
145151
instructions.append(.split(disfavoring: nilCase.label!))
146152
try compileNode(child)
153+
154+
var constructor = CaptureStructure.Constructor(
155+
.flatten)
156+
let type = child._captureStructure(&constructor).type
157+
147158
instructions += [
148159
.captureSome,
149160
.goto(label: done.label!),
150161
nilCase,
151-
.captureNil(childType: child.captureStructure.type),
162+
.captureNil(childType: type),
152163
done,
153164
.endGroup
154165
]
@@ -170,12 +181,18 @@ func compile(
170181
instructions.append(.split(disfavoring: element.label!))
171182
instructions.append(.goto(label: nilCase.label!))
172183
instructions.append(element)
184+
173185
try compileNode(child)
186+
187+
var constructor = CaptureStructure.Constructor(
188+
.flatten)
189+
let type = child._captureStructure(&constructor).type
190+
174191
instructions += [
175192
.captureSome,
176193
.goto(label: done.label!),
177194
nilCase,
178-
.captureNil(childType: child.captureStructure.type),
195+
.captureNil(childType: type),
179196
done,
180197
.endGroup
181198
]
@@ -204,7 +221,10 @@ func compile(
204221
instructions.append(.goto(label: start.label!))
205222
instructions.append(done)
206223
if childHasCaptures {
207-
instructions.append(.captureArray(childType: child.captureStructure.type))
224+
var constructor = CaptureStructure.Constructor(
225+
.flatten)
226+
let type = child._captureStructure(&constructor).type
227+
instructions.append(.captureArray(childType: type))
208228
instructions.append(.endGroup)
209229
}
210230
return
@@ -220,7 +240,10 @@ func compile(
220240
try compileNode(child)
221241
instructions.append(.split(disfavoring: start.label!))
222242
if childHasCaptures {
223-
instructions.append(.captureArray(childType: child.captureStructure.type))
243+
var constructor = CaptureStructure.Constructor(
244+
.flatten)
245+
let type = child._captureStructure(&constructor).type
246+
instructions.append(.captureArray(childType: type))
224247
instructions.append(.endGroup)
225248
}
226249
return
@@ -248,9 +271,12 @@ func compile(
248271
// cases after a succesful match.
249272
func nullifyRest(after index: Int) {
250273
for child in children.suffix(from: index + 1) where child.hasCapture {
274+
var constructor = CaptureStructure.Constructor(
275+
.flatten)
276+
let type = child._captureStructure(&constructor).type
251277
instructions.append(contentsOf: [
252278
.beginGroup,
253-
.captureNil(childType: child.captureStructure.type),
279+
.captureNil(childType: type),
254280
.endGroup,
255281
])
256282
}
@@ -276,8 +302,11 @@ func compile(
276302
nextLabel
277303
])
278304
if child.hasCapture {
305+
var constructor = CaptureStructure.Constructor(
306+
.flatten)
307+
let type = child._captureStructure(&constructor).type
279308
instructions.append(contentsOf: [
280-
.captureNil(childType: child.captureStructure.type),
309+
.captureNil(childType: type),
281310
.endGroup
282311
])
283312
}

0 commit comments

Comments
 (0)