diff --git a/Sources/_StringProcessing/Capture.swift b/Sources/_StringProcessing/Capture.swift index ecfc558fe..5b43da870 100644 --- a/Sources/_StringProcessing/Capture.swift +++ b/Sources/_StringProcessing/Capture.swift @@ -96,5 +96,3 @@ extension Sequence where Element == StructuredCapture { self.map { $0.slice(from: input) } } } - - diff --git a/Sources/_StringProcessing/Engine/Consume.swift b/Sources/_StringProcessing/Engine/Consume.swift index a4a3bf26c..4e00a34b4 100644 --- a/Sources/_StringProcessing/Engine/Consume.swift +++ b/Sources/_StringProcessing/Engine/Consume.swift @@ -24,41 +24,17 @@ extension Engine { } } -extension Engine where Input == String { - func consume( - _ input: Input, - in range: Range, - matchMode: MatchMode - ) -> (Input.Index, CaptureList)? { - if enableTracing { - print("Consume: \(input)") - } - - var cpu = makeProcessor(input: input, bounds: range, matchMode: matchMode) - let result: Input.Index? = { - while true { - switch cpu.state { - case .accept: - return cpu.currentPosition - case .fail: - return nil - case .inProgress: cpu.cycle() - } - } - }() - - if enableTracing { - if let idx = result { - print("Result: \(input[.. Input.Index? { + while true { + switch self.state { + case .accept: + return self.currentPosition + case .fail: + return nil + case .inProgress: self.cycle() } } - guard let result = result else { return nil } - - let capList = cpu.storedCaptures - return (result, CaptureList( - values: capList, referencedCaptureOffsets: program.referencedCaptureOffsets)) } } diff --git a/Sources/_StringProcessing/Executor.swift b/Sources/_StringProcessing/Executor.swift index 9de2b0b3d..c044cbf24 100644 --- a/Sources/_StringProcessing/Executor.swift +++ b/Sources/_StringProcessing/Executor.swift @@ -24,21 +24,41 @@ struct Executor { in inputRange: Range, _ mode: MatchMode ) throws -> RegexMatch? { - guard let (endIdx, capList) = engine.consume( - input, in: inputRange, matchMode: mode - ) else { + var cpu = engine.makeProcessor( + input: input, bounds: inputRange, matchMode: mode) + + guard let endIdx = cpu.consume() else { return nil } + + let capList = CaptureList( + values: cpu.storedCaptures, + referencedCaptureOffsets: engine.program.referencedCaptureOffsets) + let capStruct = engine.program.captureStructure let range = inputRange.lowerBound.. { let rawCaptures: [StructuredCapture] let referencedCaptureOffsets: [ReferenceID: Int] + let value: Any? + public var match: Match { if Match.self == (Substring, DynamicCaptures).self { // FIXME(rdar://89449323): Compiler assertion @@ -25,7 +27,15 @@ public struct RegexMatch { } else if Match.self == Substring.self { // FIXME: Plumb whole match (`.0`) through the matching engine. return input[range] as! Match + } else if rawCaptures.isEmpty, value != nil { + // FIXME: This is a workaround for whole-match values not + // being modeled as part of captures. We might want to + // switch to a model where results are alongside captures + return value! as! Match } else { + guard value == nil else { + fatalError("FIXME: what would this mean?") + } let typeErasedMatch = rawCaptures.existentialMatch(from: input[range]) return typeErasedMatch as! Match } diff --git a/Tests/RegexTests/CustomTests.swift b/Tests/RegexTests/CustomTests.swift index 692ad6c37..0ebfe4652 100644 --- a/Tests/RegexTests/CustomTests.swift +++ b/Tests/RegexTests/CustomTests.swift @@ -83,15 +83,14 @@ extension RegexTests { ("55z", .match, nil), ("55z", .firstMatch, "55")) - // FIXME: Requires we return a value instead of a range -// customTest( -// Regex { -// Numbler() -// }, -// ("ab123c", .firstMatch, 1), -// ("abc", .firstMatch, nil), -// ("55z", .match, nil), -// ("55z", .firstMatch, 5)) + customTest( + Regex { + Numbler() + }, + ("ab123c", .firstMatch, 1), + ("abc", .firstMatch, nil), + ("55z", .match, nil), + ("55z", .firstMatch, 5)) // TODO: Convert below tests to better infra. Right now // it's hard because `Match` is constrained to be