Skip to content

Commit 60b8f26

Browse files
authored
Replace DSL component nominal types with Regex. (#149)
Eliminates nominal types, e.g. `Concatenation_0_1`, returned by DSL builder methods and replace them with `Regex`. This will make sure we can ship a clean ABI even without variadic generics.
1 parent 646ba9c commit 60b8f26

File tree

4 files changed

+2147
-3410
lines changed

4 files changed

+2147
-3410
lines changed

Sources/VariadicsGenerator/VariadicsGenerator.swift

Lines changed: 58 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//
1010
//===----------------------------------------------------------------------===//
1111

12-
// swift run VariadicsGenerator --max-arity 7 > Sources/_StringProcessing/RegexDSL/Concatenation.swift
12+
// swift run VariadicsGenerator --max-arity 10 > Sources/_StringProcessing/RegexDSL/Variadics.swift
1313

1414
import ArgumentParser
1515
#if os(macOS)
@@ -96,7 +96,7 @@ let matchAssociatedTypeName = "Match"
9696
let captureAssociatedTypeName = "Capture"
9797
let patternBuilderTypeName = "RegexBuilder"
9898
let patternProtocolRequirementName = "regex"
99-
let PatternTypeBaseName = "Regex"
99+
let regexTypeName = "Regex"
100100
let baseMatchTypeName = "Substring"
101101

102102
@main
@@ -205,111 +205,62 @@ struct VariadicsGenerator: ParsableCommand {
205205
}
206206

207207
func emitConcatenation(leftArity: Int, rightArity: Int) {
208-
func emitGenericParameters(withConstraints: Bool) {
209-
output("W0, W1")
210-
outputForEach(0..<leftArity+rightArity) {
208+
func genericParameters(withConstraints: Bool) -> String {
209+
var result = "W0, W1"
210+
result += (0..<leftArity+rightArity).map {
211211
", C\($0)"
212-
}
213-
output(", ")
212+
}.joined()
213+
result += ", "
214214
if withConstraints {
215-
output("R0: \(regexProtocolName), R1: \(regexProtocolName)")
215+
result += "R0: \(regexProtocolName), R1: \(regexProtocolName)"
216216
} else {
217-
output("R0, R1")
217+
result += "R0, R1"
218218
}
219+
return result
219220
}
220221

221222
// Emit concatenation type declaration.
222223

223-
// public struct Concatenation2<W0, W1, C0, C1, R0: RegexProtocol, R1: RegexProtocol>: RegexProtocol
224-
// where R0.Match == (W0, C0), R1.Match == (W1, C1)
225-
// {
226-
// public typealias Match = (Substring, C0, C1)
227-
//
228-
// public let regex: Regex<(Substring, C0, C1)>
229-
//
230-
// public init(_ r0: R0, _ r1: R1) {
231-
// self.regex = .init(node: r0.regex.root.appending(r1.regex.root))
232-
// }
233-
// }
234-
//
235-
// extension RegexBuilder {
236-
// static func buildBlock<W0, W1, C0, C1, Combined: RegexProtocol, Next: RegexProtocol>(
237-
// combining next: Next, into combined: Combined
238-
// ) -> Concatenation2<W0, W1, C0, C1, Combined, Next> {
239-
// .init(combined, next)
240-
// }
241-
// }
242-
243-
// public struct Concatenation{n}<...>: RegexProtocol {
244-
// public typealias Match = ...
245-
// public let regex: Regex<Match>
246-
// public init(...) { ... }
247-
// }
248-
249-
let typeName = "\(concatenationStructTypeBaseName)_\(leftArity)_\(rightArity)"
250-
output("public struct \(typeName)<\n ")
251-
emitGenericParameters(withConstraints: true)
252-
output("\n>: \(regexProtocolName)")
253-
output(" where ")
254-
output("R0.Match == ")
255-
if leftArity == 0 {
256-
output("W0")
257-
} else {
258-
output("(W0")
259-
outputForEach(0..<leftArity) {
260-
", C\($0)"
261-
}
262-
output(")")
263-
}
264-
output(", R1.Match == ")
265-
if rightArity == 0 {
266-
output("W1")
267-
} else {
268-
output("(W1")
269-
outputForEach(leftArity..<leftArity+rightArity) {
270-
", C\($0)"
271-
}
272-
output(")")
273-
}
274-
output(" {\n")
275-
output(" public typealias \(matchAssociatedTypeName) = ")
276-
if leftArity+rightArity == 0 {
277-
output(baseMatchTypeName)
278-
} else {
279-
output("(\(baseMatchTypeName), ")
280-
outputForEach(0..<leftArity+rightArity, separator: ", ") {
281-
"C\($0)"
224+
let whereClause: String = {
225+
var result = " where R0.Match == "
226+
if leftArity == 0 {
227+
result += "W0"
228+
} else {
229+
result += "(W0"
230+
result += (0..<leftArity).map { ", C\($0)" }.joined()
231+
result += ")"
282232
}
283-
output(")")
284-
}
285-
output("\n")
286-
output(" public let \(patternProtocolRequirementName): \(PatternTypeBaseName)<\(matchAssociatedTypeName)>\n")
287-
output("""
288-
init(_ r0: R0, _ r1: R1) {
289-
self.regex = .init(node: r0.regex.root.appending(r1.regex.root))
290-
}
233+
result += ", R1.Match == "
234+
if rightArity == 0 {
235+
result += "W1"
236+
} else {
237+
result += "(W1"
238+
result += (leftArity..<leftArity+rightArity).map { ", C\($0)" }.joined()
239+
result += ")"
291240
}
241+
return result
242+
}()
292243

293-
""")
244+
let matchType: String = {
245+
if leftArity+rightArity == 0 {
246+
return baseMatchTypeName
247+
} else {
248+
return "(\(baseMatchTypeName), "
249+
+ (0..<leftArity+rightArity).map { "C\($0)" }.joined(separator: ", ")
250+
+ ")"
251+
}
252+
}()
294253

295254
// Emit concatenation builder.
296255
output("extension \(patternBuilderTypeName) {\n")
297256
output("""
298257
@_disfavoredOverload
299-
public static func buildBlock<
300-
""")
301-
emitGenericParameters(withConstraints: true)
302-
output("""
303-
>(
304-
combining next: R1, into combined: R0
305-
) -> \(typeName)<
306-
""")
307-
emitGenericParameters(withConstraints: false)
308-
output("""
309-
> {
310-
.init(combined, next)
258+
public static func buildBlock<\(genericParameters(withConstraints: true))>(
259+
combining next: R1, into combined: R0
260+
) -> \(regexTypeName)<\(matchType)> \(whereClause) {
261+
.init(node: combined.regex.root.appending(next.regex.root))
262+
}
311263
}
312-
}
313264
314265
""")
315266
}
@@ -327,7 +278,7 @@ struct VariadicsGenerator: ParsableCommand {
327278
output("""
328279
, R0: \(regexProtocolName), R1: \(regexProtocolName)>(
329280
combining next: R1, into combined: R0
330-
) -> Regex<
281+
) -> \(regexTypeName)<
331282
""")
332283
if leftArity == 0 {
333284
output(baseMatchTypeName)
@@ -362,14 +313,6 @@ struct VariadicsGenerator: ParsableCommand {
362313
case zeroOrMore = "many"
363314
case oneOrMore = "oneOrMore"
364315

365-
var typeName: String {
366-
switch self {
367-
case .zeroOrOne: return "_ZeroOrOne"
368-
case .zeroOrMore: return "_ZeroOrMore"
369-
case .oneOrMore: return "_OneOrMore"
370-
}
371-
}
372-
373316
var operatorName: String {
374317
switch self {
375318
case .zeroOrOne: return ".?"
@@ -404,7 +347,7 @@ struct VariadicsGenerator: ParsableCommand {
404347
}
405348
let captures = (0..<arity).map { "C\($0)" }.joined(separator: ", ")
406349
let capturesTupled = arity == 1 ? captures : "(\(captures))"
407-
let componentConstraint: String = arity == 0 ? "" :
350+
let whereClause: String = arity == 0 ? "" :
408351
"where Component.Match == (W, \(captures))"
409352
let quantifiedCaptures: String = {
410353
switch kind {
@@ -416,42 +359,34 @@ struct VariadicsGenerator: ParsableCommand {
416359
}()
417360
let matchType = arity == 0 ? baseMatchTypeName : "(\(baseMatchTypeName), \(quantifiedCaptures))"
418361
output("""
419-
public struct \(kind.typeName)_\(arity)<\(genericParameters(withConstraints: true))>: \(regexProtocolName) \(componentConstraint) {
420-
public typealias \(matchAssociatedTypeName) = \(matchType)
421-
public let regex: Regex<\(matchAssociatedTypeName)>
422-
public init(component: Component) {
423-
self.regex = .init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component.regex.root))
424-
}
425-
}
426-
427362
\(arity == 0 ? "@_disfavoredOverload" : "")
428363
public func \(kind.rawValue)<\(genericParameters(withConstraints: true))>(
429364
_ component: Component
430-
) -> \(kind.typeName)_\(arity)<\(genericParameters(withConstraints: false))> {
431-
.init(component: component)
365+
) -> \(regexTypeName)<\(matchType)> \(whereClause) {
366+
.init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component.regex.root))
432367
}
433368
434369
\(arity == 0 ? "@_disfavoredOverload" : "")
435370
public func \(kind.rawValue)<\(genericParameters(withConstraints: true))>(
436371
@RegexBuilder _ component: () -> Component
437-
) -> \(kind.typeName)_\(arity)<\(genericParameters(withConstraints: false))> {
438-
\(kind.rawValue)(component())
372+
) -> \(regexTypeName)<\(matchType)> \(whereClause) {
373+
.init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component().regex.root))
439374
}
440375
441376
\(arity == 0 ? "@_disfavoredOverload" : "")
442377
public postfix func \(kind.operatorName)<\(genericParameters(withConstraints: true))>(
443378
_ component: Component
444-
) -> \(kind.typeName)_\(arity)<\(genericParameters(withConstraints: false))> {
445-
\(kind.rawValue)(component)
379+
) -> \(regexTypeName)<\(matchType)> \(whereClause) {
380+
.init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component.regex.root))
446381
}
447382
448383
\(kind == .zeroOrOne ?
449384
"""
450385
extension RegexBuilder {
451386
public static func buildLimitedAvailability<\(genericParameters(withConstraints: true))>(
452387
_ component: Component
453-
) -> \(kind.typeName)_\(arity)<\(genericParameters(withConstraints: false))> {
454-
\(kind.rawValue)(component)
388+
) -> \(regexTypeName)<\(matchType)> \(whereClause) {
389+
.init(node: .quantification(.\(kind.astQuantifierAmount), .eager, component.regex.root))
455390
}
456391
}
457392
""" : "")
@@ -460,7 +395,6 @@ struct VariadicsGenerator: ParsableCommand {
460395
}
461396

462397
func emitAlternation(leftArity: Int, rightArity: Int) {
463-
let typeName = "_Alternation_\(leftArity)_\(rightArity)"
464398
let leftGenParams: String = {
465399
if leftArity == 0 {
466400
return "R0"
@@ -499,23 +433,16 @@ struct VariadicsGenerator: ParsableCommand {
499433
return "(\(baseMatchTypeName), \(resultCaptures))"
500434
}()
501435
output("""
502-
public struct \(typeName)<\(genericParams)>: \(regexProtocolName) \(whereClause) {
503-
public typealias Match = \(matchType)
504-
public let regex: Regex<Match>
505-
506-
public init(_ left: R0, _ right: R1) {
507-
self.regex = .init(node: left.regex.root.appendingAlternationCase(right.regex.root))
508-
}
509-
}
510-
511436
extension AlternationBuilder {
512-
public static func buildBlock<\(genericParams)>(combining next: R1, into combined: R0) -> \(typeName)<\(genericParams)> {
513-
.init(combined, next)
437+
public static func buildBlock<\(genericParams)>(
438+
combining next: R1, into combined: R0
439+
) -> \(regexTypeName)<\(matchType)> \(whereClause) {
440+
.init(node: combined.regex.root.appendingAlternationCase(next.regex.root))
514441
}
515442
}
516443
517-
public func | <\(genericParams)>(lhs: R0, rhs: R1) -> \(typeName)<\(genericParams)> {
518-
.init(lhs, rhs)
444+
public func | <\(genericParams)>(lhs: R0, rhs: R1) -> \(regexTypeName)<\(matchType)> \(whereClause) {
445+
.init(node: lhs.regex.root.appendingAlternationCase(rhs.regex.root))
519446
}
520447
521448
""")
@@ -537,7 +464,7 @@ struct VariadicsGenerator: ParsableCommand {
537464
let resultCaptures = (0..<arity).map { "C\($0)?" }.joined(separator: ", ")
538465
output("""
539466
extension AlternationBuilder {
540-
public static func buildBlock<\(genericParams)>(_ regex: R) -> Regex<(W, \(resultCaptures))> \(whereClause) {
467+
public static func buildBlock<\(genericParams)>(_ regex: R) -> \(regexTypeName)<(W, \(resultCaptures))> \(whereClause) {
541468
.init(node: .alternation([regex.regex.root]))
542469
}
543470
}

0 commit comments

Comments
 (0)