Skip to content

Commit 9920650

Browse files
committed
[WIP] Regex<Captures> -> Regex<Match>
1 parent 74f4c70 commit 9920650

File tree

10 files changed

+2804
-2443
lines changed

10 files changed

+2804
-2443
lines changed

Sources/Exercises/Participants/RegexParticipant.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ struct RegexLiteralParticipant: Participant {
3333
}
3434

3535
private func extractFromCaptures(
36-
lower: Substring, upper: Substring?, prop: Substring
36+
_ match: Tuple4<Substring, Substring, Substring?, Substring>
3737
) -> GraphemeBreakEntry? {
38-
guard let lowerScalar = Unicode.Scalar(hex: lower),
39-
let upperScalar = upper.map(Unicode.Scalar.init(hex:)) ?? lowerScalar,
40-
let property = Unicode.GraphemeBreakProperty(prop)
38+
guard let lowerScalar = Unicode.Scalar(hex: match._1),
39+
let upperScalar = match._2.map(Unicode.Scalar.init(hex:)) ?? lowerScalar,
40+
let property = Unicode.GraphemeBreakProperty(match._3)
4141
else {
4242
return nil
4343
}
@@ -48,8 +48,8 @@ private func extractFromCaptures(
4848
private func graphemeBreakPropertyData<RP: RegexProtocol>(
4949
forLine line: String,
5050
using regex: RP
51-
) -> GraphemeBreakEntry? where RP.Capture == (Substring, Substring?, Substring) {
52-
line.match(regex).map(\.captures).flatMap(extractFromCaptures)
51+
) -> GraphemeBreakEntry? where RP.Match == Tuple4<Substring, Substring, Substring?, Substring> {
52+
line.match(regex).map(\.match).flatMap(extractFromCaptures)
5353
}
5454

5555
private func graphemeBreakPropertyData(
@@ -75,5 +75,5 @@ private func graphemeBreakPropertyDataLiteral(
7575
return graphemeBreakPropertyData(
7676
forLine: line,
7777
using: r(#"([0-9A-F]+)(?:\.\.([0-9A-F]+))?\s+;\s+(\w+).*"#,
78-
capturing: (Substring, Substring?, Substring).self))
78+
matching: Tuple4<Substring, Substring, Substring?, Substring>.self))
7979
}

Sources/VariadicsGenerator/VariadicsGenerator.swift

Lines changed: 107 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
// swift run VariadicsGenerator --max-arity 7 > Sources/RegexDSL/Concatenation.swift
1+
// swift run VariadicsGenerator --max-arity 7 > Sources/_StringProcessing/RegexDSL/Concatenation.swift
22

33
import ArgumentParser
44

55
struct Permutation {
66
let arity: Int
77
// 1 -> no extra constraint
8-
// 0 -> where T.Capture: NoCaptureProtocol
8+
// 0 -> where T.Match: NoCaptureProtocol
99
let bits: Int64
1010

1111
func isCaptureless(at index: Int) -> Bool {
@@ -77,8 +77,6 @@ func outputForEach<C: Collection>(
7777
if let lt = lineTerminator {
7878
let indent = needsSep ? " " : " "
7979
output("\(lt)\n\(indent)")
80-
} else if needsSep {
81-
output(" ")
8280
}
8381
}
8482
}
@@ -87,12 +85,13 @@ typealias Counter = Int64
8785
let patternProtocolName = "RegexProtocol"
8886
let concatenationStructTypeBaseName = "Concatenate"
8987
let capturingGroupTypeBaseName = "CapturingGroup"
88+
let matchAssociatedTypeName = "Match"
9089
let captureAssociatedTypeName = "Capture"
9190
let patternBuilderTypeName = "RegexBuilder"
9291
let patternProtocolRequirementName = "regex"
9392
let PatternTypeBaseName = "Regex"
94-
let emptyProtocolName = "EmptyProtocol"
95-
let emptyStructName = "Empty"
93+
let emptyProtocolName = "EmptyCaptureProtocol"
94+
let baseMatchTypeName = "Substring"
9695

9796
@main
9897
struct VariadicsGenerator: ParsableCommand {
@@ -114,6 +113,10 @@ struct VariadicsGenerator: ParsableCommand {
114113
115114
""")
116115

116+
for arity in 2...maxArity+1 {
117+
emitTupleStruct(arity: arity)
118+
}
119+
117120
for arity in minArity...maxArity {
118121
for permutation in Permutations(arity: arity) {
119122
emitConcatenation(permutation: permutation)
@@ -124,42 +127,123 @@ struct VariadicsGenerator: ParsableCommand {
124127
output("// END AUTO-GENERATED CONTENT")
125128
}
126129

130+
func emitTupleStruct(arity: Int) {
131+
output("@frozen public struct Tuple\(arity)<")
132+
outputForEach(0..<arity, separator: ", ") {
133+
"_\($0)"
134+
}
135+
output(">: TupleProtocol {\n")
136+
outputForEach(0..<arity, separator: "") {
137+
" public var _\($0): _\($0)\n"
138+
}
139+
output("\n init(_coercing: [Any]) {\n")
140+
outputForEach(0..<arity, separator: "") {
141+
" self._\($0) = _coercing[\($0)] as! _\($0)\n"
142+
}
143+
output(" }\n")
144+
145+
output("}\n")
146+
output("extension Tuple\(arity): \(emptyProtocolName) where ")
147+
outputForEach(1..<arity, separator: ", ") {
148+
"_\($0): \(emptyProtocolName)"
149+
}
150+
output(" {}\n")
151+
output("extension Tuple\(arity): MatchProtocol {\n")
152+
output(" public typealias Capture = ")
153+
if arity == 2 {
154+
output("_1")
155+
} else {
156+
output("Tuple\(arity-1)<")
157+
outputForEach(1..<arity, separator: ", ") {
158+
"_\($0)"
159+
}
160+
output(">")
161+
}
162+
// `public var tuple: (_0, ...) { (_0, ...) }`
163+
output("\n public var tuple: (")
164+
outputForEach(0..<arity, separator: ", ") {
165+
"_\($0)"
166+
}
167+
output(") { (")
168+
outputForEach(0..<arity, separator: ", ") {
169+
"self._\($0)"
170+
}
171+
output(") }\n")
172+
// `public init(_0: _0, ...) { ... }`
173+
output("\n public init(")
174+
outputForEach(0..<arity, separator: ", ") {
175+
"_ _\($0): _\($0)"
176+
}
177+
output(") {\n")
178+
outputForEach(0..<arity, separator: "") {
179+
" self._\($0) = _\($0)\n"
180+
}
181+
output(" }")
182+
output("\n}\n")
183+
// Equatable
184+
output("extension Tuple\(arity): Equatable where ")
185+
outputForEach(0..<arity, separator: ", ") {
186+
"_\($0): Equatable"
187+
}
188+
output(" {\n")
189+
output(" public static func == (lhs: Self, rhs: Self) -> Bool {\n")
190+
output(" ")
191+
outputForEach(0..<arity, separator: " && ") {
192+
"lhs._\($0) == rhs._\($0)"
193+
}
194+
output("\n }")
195+
output("}\n")
196+
}
197+
127198
func emitConcatenation(permutation: Permutation) {
128199
let arity = permutation.arity
200+
201+
func emitGenericParameters(withConstraints: Bool) {
202+
outputForEach(0..<arity, separator: ", ") {
203+
var base = "T\($0)"
204+
if withConstraints {
205+
base += ": \(patternProtocolName)"
206+
}
207+
return base
208+
}
209+
}
210+
129211
// Emit concatenation type declarations.
130212
// public struct Concatenation{n}_{perm}<...>: RegexProtocol {
131-
// public typealias Capture = ...
132-
// public let regex: Regex
213+
// public typealias Match = ...
214+
// public let regex: Regex<Match>
133215
// public init(...) { ... }
134216
// }
135-
let typeName = "\(concatenationStructTypeBaseName)\(arity)_\(permutation.identifier)"
217+
let typeName =
218+
"\(concatenationStructTypeBaseName)\(arity)_\(permutation.identifier)"
136219
output("public struct \(typeName)<\n ")
137-
outputForEach(0..<arity, separator: ",") { "T\($0): \(patternProtocolName)" }
220+
emitGenericParameters(withConstraints: true)
138221
output("\n>: \(patternProtocolName)")
139222
if permutation.hasCaptureless {
140223
output(" where ")
141-
outputForEach(permutation.capturelessIndices, separator: ",") {
142-
"T\($0).\(captureAssociatedTypeName): \(emptyProtocolName)"
224+
outputForEach(permutation.capturelessIndices, separator: ", ") {
225+
"T\($0).\(matchAssociatedTypeName).\(captureAssociatedTypeName): \(emptyProtocolName)"
143226
}
144227
}
145228
output(" {\n")
146229
let captureIndices = permutation.captureIndices
147-
output(" public typealias \(captureAssociatedTypeName) = ")
230+
output(" public typealias \(matchAssociatedTypeName) = ")
148231
let captureElements = captureIndices
149-
.map { "T\($0).\(captureAssociatedTypeName)" }
232+
.map { "T\($0).\(matchAssociatedTypeName).\(captureAssociatedTypeName)" }
150233
if captureElements.isEmpty {
151-
output(emptyStructName)
234+
output(baseMatchTypeName)
152235
} else {
153-
output("(\(captureElements.joined(separator: ", ")))")
236+
let count = captureElements.count + 1
237+
output("Tuple\(count)<\(baseMatchTypeName), \(captureElements.joined(separator: ", "))>")
154238
}
155239
output("\n")
156-
output(" public let \(patternProtocolRequirementName): \(PatternTypeBaseName)<\(captureAssociatedTypeName)>\n")
240+
output(" public let \(patternProtocolRequirementName): \(PatternTypeBaseName)<\(matchAssociatedTypeName)>\n")
157241
output(" init(")
158-
outputForEach(0..<arity, separator: ",") { "_ x\($0): T\($0)" }
242+
outputForEach(0..<arity, separator: ", ") { "_ x\($0): T\($0)" }
159243
output(") {\n")
160244
output(" \(patternProtocolRequirementName) = .init(ast: concat(\n ")
161245
outputForEach(
162-
0..<arity, separator: ",", lineTerminator: ""
246+
0..<arity, separator: ", ", lineTerminator: ""
163247
) { i in
164248
"x\(i).\(patternProtocolRequirementName).ast"
165249
}
@@ -169,14 +253,14 @@ struct VariadicsGenerator: ParsableCommand {
169253
// Emit concatenation builders.
170254
output("extension \(patternBuilderTypeName) {\n")
171255
output(" public static func buildBlock<")
172-
outputForEach(0..<arity, separator: ",") { "T\($0)" }
256+
emitGenericParameters(withConstraints: true)
173257
output(">(\n ")
174-
outputForEach(0..<arity, separator: ",") { "_ x\($0): T\($0)" }
258+
outputForEach(0..<arity, separator: ", ") { "_ x\($0): T\($0)" }
175259
output("\n ) -> \(typeName)<")
176-
outputForEach(0..<arity, separator: ",") { "T\($0)" }
260+
emitGenericParameters(withConstraints: false)
177261
output("> {\n")
178262
output(" \(typeName)(")
179-
outputForEach(0..<arity, separator: ",") { "x\($0)" }
263+
outputForEach(0..<arity, separator: ", ") { "x\($0)" }
180264
output(")\n }\n}\n\n")
181265
}
182266
}

Sources/_StringProcessing/Capture.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ extension Capture {
2929
guard let first = elements.first else {
3030
return [Any]()
3131
}
32-
// When the array is not empty, infer the concrete `Element `type from the first element.
32+
// When the array is not empty, infer the concrete `Element `type from the
33+
// first element.
3334
func helper<T>(_ first: T) -> Any {
3435
var castElements = [first]
3536
for element in elements.dropFirst() {
@@ -42,4 +43,17 @@ extension Capture {
4243
return subcapture?.value as Any
4344
}
4445
}
46+
47+
private func prepending(_ newElement: Any) -> Self {
48+
switch self {
49+
case .atom, .optional, .array:
50+
return .tuple([.atom(newElement), self])
51+
case .tuple(let elements):
52+
return .tuple([.atom(newElement)] + elements)
53+
}
54+
}
55+
56+
func matchValue(withWholeMatch wholeMatch: Substring) -> Any {
57+
prepending(wholeMatch).value
58+
}
4559
}

Sources/_StringProcessing/RegexDSL/Builder.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ public enum RegexBuilder {
1212
component
1313
}
1414

15-
public static func buildLimitedAvailability<R: RegexProtocol>(_ component: R) -> Optionally<R> {
15+
public static func buildLimitedAvailability<R: RegexProtocol>(
16+
_ component: R
17+
) -> Optionally<R> {
1618
.init(component)
1719
}
1820
}

0 commit comments

Comments
 (0)