Skip to content

Commit fed4c53

Browse files
authored
Throwing customization hooks (swiftlang#261)
* Throwing customization hooks * Adds test to try out throwing custom code. * Adds processor support. * Add throws to capture transform API, plumbing * Remove non-failable try-capture overloads
1 parent 5af9ca5 commit fed4c53

File tree

11 files changed

+339
-851
lines changed

11 files changed

+339
-851
lines changed

Sources/RegexBuilder/Variadics.swift

Lines changed: 134 additions & 688 deletions
Large diffs are not rendered by default.

Sources/VariadicsGenerator/VariadicsGenerator.swift

Lines changed: 12 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -615,35 +615,6 @@ struct VariadicsGenerator: ParsableCommand {
615615
self.init(node: .capture(reference: reference.id, component.regex.root))
616616
}
617617
618-
\(disfavored)\
619-
public init<\(genericParams), NewCapture>(
620-
_ component: R,
621-
transform: @escaping (Substring) -> NewCapture
622-
) \(whereClauseTransformed) {
623-
self.init(node: .capture(.transform(
624-
CaptureTransform(resultType: NewCapture.self) {
625-
transform($0) as Any
626-
},
627-
component.regex.root)))
628-
}
629-
630-
\(disfavored)\
631-
public init<\(genericParams), NewCapture>(
632-
_ component: R,
633-
as reference: Reference<NewCapture>,
634-
transform: @escaping (Substring) -> NewCapture
635-
) \(whereClauseTransformed) {
636-
self.init(node: .capture(
637-
reference: reference.id,
638-
.transform(
639-
CaptureTransform(resultType: NewCapture.self) {
640-
transform($0) as Any
641-
},
642-
component.regex.root)))
643-
}
644-
}
645-
646-
extension TryCapture {
647618
\(disfavored)\
648619
public init<\(genericParams), NewCapture>(
649620
_ component: R,
@@ -670,15 +641,17 @@ struct VariadicsGenerator: ParsableCommand {
670641
},
671642
component.regex.root)))
672643
}
644+
}
673645
646+
extension TryCapture {
674647
\(disfavored)\
675648
public init<\(genericParams), NewCapture>(
676649
_ component: R,
677-
transform: @escaping (Substring) -> NewCapture?
650+
transform: @escaping (Substring) throws -> NewCapture?
678651
) \(whereClauseTransformed) {
679652
self.init(node: .capture(.transform(
680653
CaptureTransform(resultType: NewCapture.self) {
681-
transform($0) as Any?
654+
try transform($0) as Any?
682655
},
683656
component.regex.root)))
684657
}
@@ -687,13 +660,13 @@ struct VariadicsGenerator: ParsableCommand {
687660
public init<\(genericParams), NewCapture>(
688661
_ component: R,
689662
as reference: Reference<NewCapture>,
690-
transform: @escaping (Substring) -> NewCapture?
663+
transform: @escaping (Substring) throws -> NewCapture?
691664
) \(whereClauseTransformed) {
692665
self.init(node: .capture(
693666
reference: reference.id,
694667
.transform(
695668
CaptureTransform(resultType: NewCapture.self) {
696-
transform($0) as Any?
669+
try transform($0) as Any?
697670
},
698671
component.regex.root)))
699672
}
@@ -719,35 +692,6 @@ struct VariadicsGenerator: ParsableCommand {
719692
component().regex.root))
720693
}
721694
722-
\(disfavored)\
723-
public init<\(genericParams), NewCapture>(
724-
@\(concatBuilderName) _ component: () -> R,
725-
transform: @escaping (Substring) -> NewCapture
726-
) \(whereClauseTransformed) {
727-
self.init(node: .capture(.transform(
728-
CaptureTransform(resultType: NewCapture.self) {
729-
transform($0) as Any
730-
},
731-
component().regex.root)))
732-
}
733-
734-
\(disfavored)\
735-
public init<\(genericParams), NewCapture>(
736-
as reference: Reference<NewCapture>,
737-
@\(concatBuilderName) _ component: () -> R,
738-
transform: @escaping (Substring) -> NewCapture
739-
) \(whereClauseTransformed) {
740-
self.init(node: .capture(
741-
reference: reference.id,
742-
.transform(
743-
CaptureTransform(resultType: NewCapture.self) {
744-
transform($0) as Any
745-
},
746-
component().regex.root)))
747-
}
748-
}
749-
750-
extension TryCapture {
751695
\(disfavored)\
752696
public init<\(genericParams), NewCapture>(
753697
@\(concatBuilderName) _ component: () -> R,
@@ -774,15 +718,17 @@ struct VariadicsGenerator: ParsableCommand {
774718
},
775719
component().regex.root)))
776720
}
721+
}
777722
723+
extension TryCapture {
778724
\(disfavored)\
779725
public init<\(genericParams), NewCapture>(
780726
@\(concatBuilderName) _ component: () -> R,
781-
transform: @escaping (Substring) -> NewCapture?
727+
transform: @escaping (Substring) throws -> NewCapture?
782728
) \(whereClauseTransformed) {
783729
self.init(node: .capture(.transform(
784730
CaptureTransform(resultType: NewCapture.self) {
785-
transform($0) as Any?
731+
try transform($0) as Any?
786732
},
787733
component().regex.root)))
788734
}
@@ -791,13 +737,13 @@ struct VariadicsGenerator: ParsableCommand {
791737
public init<\(genericParams), NewCapture>(
792738
as reference: Reference<NewCapture>,
793739
@\(concatBuilderName) _ component: () -> R,
794-
transform: @escaping (Substring) -> NewCapture?
740+
transform: @escaping (Substring) throws -> NewCapture?
795741
) \(whereClauseTransformed) {
796742
self.init(node: .capture(
797743
reference: reference.id,
798744
.transform(
799745
CaptureTransform(resultType: NewCapture.self) {
800-
transform($0) as Any?
746+
try transform($0) as Any?
801747
},
802748
component().regex.root)))
803749
}

Sources/_RegexParser/Regex/AST/AST.swift

Lines changed: 0 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -304,78 +304,3 @@ extension AST {
304304
}
305305
}
306306
}
307-
308-
// FIXME: Get this out of here
309-
public struct CaptureTransform: Equatable, Hashable, CustomStringConvertible {
310-
public enum Closure {
311-
case nonfailable((Substring) -> Any)
312-
case failable((Substring) -> Any?)
313-
case throwing((Substring) throws -> Any)
314-
}
315-
public let resultType: Any.Type
316-
public let closure: Closure
317-
318-
public init(resultType: Any.Type, closure: Closure) {
319-
self.resultType = resultType
320-
self.closure = closure
321-
}
322-
323-
public init(
324-
resultType: Any.Type,
325-
_ closure: @escaping (Substring) -> Any
326-
) {
327-
self.init(resultType: resultType, closure: .nonfailable(closure))
328-
}
329-
330-
public init(
331-
resultType: Any.Type,
332-
_ closure: @escaping (Substring) -> Any?
333-
) {
334-
self.init(resultType: resultType, closure: .failable(closure))
335-
}
336-
337-
public init(
338-
resultType: Any.Type,
339-
_ closure: @escaping (Substring) throws -> Any
340-
) {
341-
self.init(resultType: resultType, closure: .throwing(closure))
342-
}
343-
344-
public func callAsFunction(_ input: Substring) -> Any? {
345-
switch closure {
346-
case .nonfailable(let closure):
347-
let result = closure(input)
348-
assert(type(of: result) == resultType)
349-
return result
350-
case .failable(let closure):
351-
guard let result = closure(input) else {
352-
return nil
353-
}
354-
assert(type(of: result) == resultType)
355-
return result
356-
case .throwing(let closure):
357-
do {
358-
let result = try closure(input)
359-
assert(type(of: result) == resultType)
360-
return result
361-
} catch {
362-
return nil
363-
}
364-
}
365-
}
366-
367-
public static func == (lhs: CaptureTransform, rhs: CaptureTransform) -> Bool {
368-
unsafeBitCast(lhs.closure, to: (Int, Int).self) ==
369-
unsafeBitCast(rhs.closure, to: (Int, Int).self)
370-
}
371-
372-
public func hash(into hasher: inout Hasher) {
373-
let (fn, ctx) = unsafeBitCast(closure, to: (Int, Int).self)
374-
hasher.combine(fn)
375-
hasher.combine(ctx)
376-
}
377-
378-
public var description: String {
379-
"<transform result_type=\(resultType)>"
380-
}
381-
}

Sources/_StringProcessing/ByteCodeGen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ extension Compiler.ByteCodeGen {
317317
) throws {
318318
let transform = builder.makeTransformFunction {
319319
input, range in
320-
t(input[range])
320+
try t(input[range])
321321
}
322322
builder.buildBeginCapture(cap)
323323
try emitNode(child)

Sources/_StringProcessing/Engine/Consume.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ extension Engine {
2525
}
2626

2727
extension Processor where Input == String {
28+
// TODO: Should we throw here?
2829
mutating func consume() -> Input.Index? {
2930
while true {
3031
switch self.state {

Sources/_StringProcessing/Engine/MEProgram.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ import _RegexParser
1414
struct MEProgram<Input: Collection> where Input.Element: Equatable {
1515
typealias ConsumeFunction = (Input, Range<Input.Index>) -> Input.Index?
1616
typealias AssertionFunction =
17-
(Input, Input.Index, Range<Input.Index>) -> Bool
17+
(Input, Input.Index, Range<Input.Index>) throws -> Bool
1818
typealias TransformFunction =
19-
(Input, Range<Input.Index>) -> Any?
19+
(Input, Range<Input.Index>) throws -> Any?
2020
typealias MatcherFunction =
21-
(Input, Input.Index, Range<Input.Index>) -> (Input.Index, Any)?
21+
(Input, Input.Index, Range<Input.Index>) throws -> (Input.Index, Any)?
2222

2323
var instructions: InstructionList<Instruction>
2424

Sources/_StringProcessing/Engine/Processor.swift

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ struct Processor<
5151

5252
var state: State = .inProgress
5353

54+
var failureReason: Error? = nil
55+
5456
var isTracingEnabled: Bool
5557

5658
var storedCaptures: Array<_StoredCapture>
@@ -181,6 +183,13 @@ extension Processor {
181183
registers.ints = intRegisters
182184
}
183185

186+
mutating func abort(_ e: Error? = nil) {
187+
if let e = e {
188+
self.failureReason = e
189+
}
190+
self.state = .fail
191+
}
192+
184193
mutating func tryAccept() {
185194
switch (currentPosition, matchMode) {
186195
// When reaching the end of the match bounds or when we are only doing a
@@ -355,24 +364,34 @@ extension Processor {
355364
case .assertBy:
356365
let reg = payload.assertion
357366
let assertion = registers[reg]
358-
guard assertion(input, currentPosition, bounds) else {
359-
signalFailure()
367+
do {
368+
guard try assertion(input, currentPosition, bounds) else {
369+
signalFailure()
370+
return
371+
}
372+
} catch {
373+
abort(error)
360374
return
361375
}
362376
controller.step()
363377

364378
case .matchBy:
365379
let (matcherReg, valReg) = payload.pairedMatcherValue
366380
let matcher = registers[matcherReg]
367-
guard let (nextIdx, val) = matcher(
368-
input, currentPosition, bounds
369-
) else {
370-
signalFailure()
381+
do {
382+
guard let (nextIdx, val) = try matcher(
383+
input, currentPosition, bounds
384+
) else {
385+
signalFailure()
386+
return
387+
}
388+
registers[valReg] = val
389+
advance(to: nextIdx)
390+
controller.step()
391+
} catch {
392+
abort(error)
371393
return
372394
}
373-
registers[valReg] = val
374-
advance(to: nextIdx)
375-
controller.step()
376395

377396
case .print:
378397
// TODO: Debug stream
@@ -431,14 +450,18 @@ extension Processor {
431450
fatalError(
432451
"Unreachable: transforming without a capture")
433452
}
434-
// FIXME: Pass input or the slice?
435-
guard let value = transform(input, range) else {
436-
signalFailure()
453+
do {
454+
// FIXME: Pass input or the slice?
455+
guard let value = try transform(input, range) else {
456+
signalFailure()
457+
return
458+
}
459+
storedCaptures[capNum].registerValue(value)
460+
controller.step()
461+
} catch {
462+
abort(error)
437463
return
438464
}
439-
storedCaptures[capNum].registerValue(value)
440-
441-
controller.step()
442465

443466
case .captureValue:
444467
let (val, cap) = payload.pairedValueCapture

Sources/_StringProcessing/Executor.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ struct Executor {
2828
input: input, bounds: inputRange, matchMode: mode)
2929

3030
guard let endIdx = cpu.consume() else {
31+
if let e = cpu.failureReason {
32+
throw e
33+
}
3134
return nil
3235
}
3336

0 commit comments

Comments
 (0)