Skip to content

Commit bfc3335

Browse files
authored
Merge pull request #541 from Azoy/errors-what-errors
Throw error when Output is wrong type
2 parents 7b7e35d + 7cad6cb commit bfc3335

File tree

4 files changed

+35
-7
lines changed

4 files changed

+35
-7
lines changed

Sources/_StringProcessing/Compiler.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@ enum RegexCompilationError: Error, CustomStringConvertible {
4747
// TODO: Source location?
4848
case uncapturedReference
4949

50+
case incorrectOutputType(incorrect: Any.Type, correct: Any.Type)
51+
5052
var description: String {
5153
switch self {
5254
case .uncapturedReference:
5355
return "Found a reference used before it captured any match."
56+
case .incorrectOutputType(let incorrect, let correct):
57+
return "Cast to incorrect type 'Regex<\(incorrect)>', expected 'Regex<\(correct)>'"
5458
}
5559
}
5660
}

Sources/_StringProcessing/Regex/AnyRegexOutput.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,18 @@ extension Regex {
161161
_ pattern: String,
162162
as: Output.Type = Output.self
163163
) throws {
164-
self.init(ast: try parse(pattern, .traditional))
164+
let regex = Regex(ast: try parse(pattern, .traditional))
165+
166+
let (isSuccess, correctType) = regex._verifyType()
167+
168+
guard isSuccess else {
169+
throw RegexCompilationError.incorrectOutputType(
170+
incorrect: Output.self,
171+
correct: correctType
172+
)
173+
}
174+
175+
self = regex
165176
}
166177

167178
/// Produces a regex that matches `verbatim` exactly, as though every
@@ -217,7 +228,8 @@ extension Regex {
217228
as: Output.Type = Output.self
218229
) {
219230
self.init(node: erased.root)
220-
guard self._verifyType() else {
231+
232+
guard _verifyType().0 else {
221233
return nil
222234
}
223235
}

Sources/_StringProcessing/Utility/TypeVerification.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313

1414
@available(SwiftStdlib 5.7, *)
1515
extension Regex {
16-
internal func _verifyType() -> Bool {
16+
internal func _verifyType() -> (Bool, Any.Type) {
1717
guard Output.self != AnyRegexOutput.self else {
18-
return true
18+
return (true, Output.self)
1919
}
2020

2121
var tupleElements: [Any.Type] = []
2222
var labels = ""
2323

2424
for capture in program.tree.captureList.captures {
25-
var captureType: Any.Type = capture.type ?? Substring.self
25+
var captureType = capture.type
2626
var i = capture.optionalDepth
2727

2828
while i != 0 {
@@ -41,7 +41,8 @@ extension Regex {
4141

4242
// If we have no captures, then our Regex must be Regex<Substring>.
4343
if tupleElements.count == 1 {
44-
return Output.self == program.tree.root.wholeMatchType
44+
let wholeMatchType = program.tree.root.wholeMatchType
45+
return (Output.self == wholeMatchType, wholeMatchType)
4546
}
4647

4748
let createdType = TypeConstruction.tupleType(
@@ -52,6 +53,6 @@ extension Regex {
5253
labels: labels.all { $0 == " " } ? nil : labels
5354
)
5455

55-
return Output.self == createdType
56+
return (Output.self == createdType, createdType)
5657
}
5758
}

Tests/RegexBuilderTests/AnyRegexOutputTests.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,17 @@ extension RegexDSLTests {
218218
noteOutput
219219
)
220220

221+
// Run-time strings (errors)
222+
XCTAssertThrowsError(try Regex("abc", as: (Substring, Substring).self))
223+
XCTAssertThrowsError(try Regex("(abc)", as: Substring.self))
224+
XCTAssertThrowsError(try Regex("(?<test>abc)", as: (Substring, Substring).self))
225+
XCTAssertThrowsError(try Regex("(?<test>abc)?", as: (Substring, test: Substring).self))
226+
227+
XCTAssertNoThrow(try Regex("abc", as: Substring.self))
228+
XCTAssertNoThrow(try Regex("(abc)", as: (Substring, Substring).self))
229+
XCTAssertNoThrow(try Regex("(?<test>abc)", as: (Substring, test: Substring).self))
230+
XCTAssertNoThrow(try Regex("(?<test>abc)?", as: (Substring, test: Substring?).self))
231+
221232
// Builders
222233
check(
223234
Regex {

0 commit comments

Comments
 (0)