Skip to content

Commit 3f556cb

Browse files
committed
WIP: refactoring
1 parent 612f104 commit 3f556cb

File tree

2 files changed

+116
-101
lines changed

2 files changed

+116
-101
lines changed

Sources/_StringProcessing/RegexDSL/Core.swift

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,6 @@
1111

1212
import _MatchingEngine
1313

14-
@dynamicMemberLookup
15-
public struct RegexMatch<Match> {
16-
public let range: Range<String.Index>
17-
public let match: Match
18-
19-
public subscript<T>(dynamicMember keyPath: KeyPath<Match, T>) -> T {
20-
match[keyPath: keyPath]
21-
}
22-
}
2314

2415
/// A type that represents a regular expression.
2516
public protocol RegexProtocol {
@@ -134,93 +125,7 @@ public struct Regex<Match: MatchProtocol>: RegexProtocol {
134125
}
135126
}
136127

137-
extension RegexProtocol {
138-
public func match(in input: String) -> RegexMatch<Match>? {
139-
_match(
140-
input, in: input.startIndex..<input.endIndex)
141-
}
142-
public func match(in input: Substring) -> RegexMatch<Match>? {
143-
_match(
144-
input.base, in: input.startIndex..<input.endIndex)
145-
}
146128

147-
// FIXME: This is mostly hacky because we go down two different paths based on
148-
// whether there are captures. This will be cleaned up once we deprecate the
149-
// legacy virtual machines.
150-
func _match(
151-
_ input: String,
152-
in inputRange: Range<String.Index>,
153-
mode: MatchMode = .wholeString
154-
) -> RegexMatch<Match>? {
155-
// Casts a Swift tuple to the custom `Tuple<n>`, assuming their memory
156-
// layout is compatible.
157-
func bitCastToMatch<T>(_ x: T) -> Match {
158-
assert(MemoryLayout<T>.size == MemoryLayout<Match>.size)
159-
return unsafeBitCast(x, to: Match.self)
160-
}
161-
// TODO: Remove this branch when the matching engine supports captures.
162-
if regex.hasCapture {
163-
let vm = HareVM(program: regex.program.legacyLoweredProgram)
164-
guard let (range, captures) = vm.execute(
165-
input: input, in: inputRange, mode: mode
166-
)?.destructure else {
167-
return nil
168-
}
169-
let convertedMatch: Match
170-
if Match.self == Tuple2<Substring, DynamicCaptures>.self {
171-
convertedMatch = Tuple2(
172-
input[range], DynamicCaptures(captures)
173-
) as! Match
174-
} else {
175-
let typeErasedMatch = captures.matchValue(
176-
withWholeMatch: input[range]
177-
)
178-
convertedMatch = _openExistential(typeErasedMatch, do: bitCastToMatch)
179-
}
180-
return RegexMatch(range: range, match: convertedMatch)
181-
}
182-
183-
let executor = Executor(program: regex.program.loweredProgram)
184-
guard let result = executor.execute(
185-
input: input, in: inputRange, mode: mode
186-
) else {
187-
return nil
188-
}
189-
let convertedMatch: Match
190-
if Match.self == Tuple2<Substring, DynamicCaptures>.self {
191-
convertedMatch = Tuple2(
192-
input[result.range], DynamicCaptures.empty
193-
) as! Match
194-
} else {
195-
assert(Match.self == Substring.self)
196-
convertedMatch = input[result.range] as! Match
197-
}
198-
return RegexMatch(range: result.range, match: convertedMatch)
199-
}
200-
}
201-
202-
extension String {
203-
public func match<R: RegexProtocol>(_ regex: R) -> RegexMatch<R.Match>? {
204-
regex.match(in: self)
205-
}
206-
207-
public func match<R: RegexProtocol>(
208-
@RegexBuilder _ content: () -> R
209-
) -> RegexMatch<R.Match>? {
210-
match(content())
211-
}
212-
}
213-
extension Substring {
214-
public func match<R: RegexProtocol>(_ regex: R) -> RegexMatch<R.Match>? {
215-
regex.match(in: self)
216-
}
217-
218-
public func match<R: RegexProtocol>(
219-
@RegexBuilder _ content: () -> R
220-
) -> RegexMatch<R.Match>? {
221-
match(content())
222-
}
223-
}
224129
public struct MockRegexLiteral<Match: MatchProtocol>: RegexProtocol {
225130
public typealias MatchValue = Substring
226131
public let regex: Regex<Match>
@@ -247,10 +152,4 @@ public struct EmptyCapture: EmptyCaptureProtocol {}
247152
extension Array: EmptyCaptureProtocol where Element: EmptyCaptureProtocol {}
248153
extension Optional: EmptyCaptureProtocol where Wrapped: EmptyCaptureProtocol {}
249154

250-
public protocol MatchProtocol {
251-
associatedtype Capture
252-
}
253-
extension Substring: MatchProtocol {
254-
public typealias Capture = EmptyCapture
255-
}
256155

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
public protocol MatchProtocol {
13+
associatedtype Capture
14+
}
15+
extension Substring: MatchProtocol {
16+
public typealias Capture = EmptyCapture
17+
}
18+
19+
@dynamicMemberLookup
20+
public struct RegexMatch<Match> {
21+
public let range: Range<String.Index>
22+
public let match: Match
23+
24+
public subscript<T>(dynamicMember keyPath: KeyPath<Match, T>) -> T {
25+
match[keyPath: keyPath]
26+
}
27+
}
28+
29+
extension RegexProtocol {
30+
public func match(in input: String) -> RegexMatch<Match>? {
31+
_match(
32+
input, in: input.startIndex..<input.endIndex)
33+
}
34+
public func match(in input: Substring) -> RegexMatch<Match>? {
35+
_match(
36+
input.base, in: input.startIndex..<input.endIndex)
37+
}
38+
39+
// FIXME: This is mostly hacky because we go down two different paths based on
40+
// whether there are captures. This will be cleaned up once we deprecate the
41+
// legacy virtual machines.
42+
func _match(
43+
_ input: String,
44+
in inputRange: Range<String.Index>,
45+
mode: MatchMode = .wholeString
46+
) -> RegexMatch<Match>? {
47+
// Casts a Swift tuple to the custom `Tuple<n>`, assuming their memory
48+
// layout is compatible.
49+
func bitCastToMatch<T>(_ x: T) -> Match {
50+
assert(MemoryLayout<T>.size == MemoryLayout<Match>.size)
51+
return unsafeBitCast(x, to: Match.self)
52+
}
53+
// TODO: Remove this branch when the matching engine supports captures.
54+
if regex.hasCapture {
55+
let vm = HareVM(program: regex.program.legacyLoweredProgram)
56+
guard let (range, captures) = vm.execute(
57+
input: input, in: inputRange, mode: mode
58+
)?.destructure else {
59+
return nil
60+
}
61+
let convertedMatch: Match
62+
if Match.self == Tuple2<Substring, DynamicCaptures>.self {
63+
convertedMatch = Tuple2(
64+
input[range], DynamicCaptures(captures)
65+
) as! Match
66+
} else {
67+
let typeErasedMatch = captures.matchValue(
68+
withWholeMatch: input[range]
69+
)
70+
convertedMatch = _openExistential(typeErasedMatch, do: bitCastToMatch)
71+
}
72+
return RegexMatch(range: range, match: convertedMatch)
73+
}
74+
75+
let executor = Executor(program: regex.program.loweredProgram)
76+
guard let result = executor.execute(
77+
input: input, in: inputRange, mode: mode
78+
) else {
79+
return nil
80+
}
81+
let convertedMatch: Match
82+
if Match.self == Tuple2<Substring, DynamicCaptures>.self {
83+
convertedMatch = Tuple2(
84+
input[result.range], DynamicCaptures.empty
85+
) as! Match
86+
} else {
87+
assert(Match.self == Substring.self)
88+
convertedMatch = input[result.range] as! Match
89+
}
90+
return RegexMatch(range: result.range, match: convertedMatch)
91+
}
92+
}
93+
94+
extension String {
95+
public func match<R: RegexProtocol>(_ regex: R) -> RegexMatch<R.Match>? {
96+
regex.match(in: self)
97+
}
98+
99+
public func match<R: RegexProtocol>(
100+
@RegexBuilder _ content: () -> R
101+
) -> RegexMatch<R.Match>? {
102+
match(content())
103+
}
104+
}
105+
106+
extension Substring {
107+
public func match<R: RegexProtocol>(_ regex: R) -> RegexMatch<R.Match>? {
108+
regex.match(in: self)
109+
}
110+
111+
public func match<R: RegexProtocol>(
112+
@RegexBuilder _ content: () -> R
113+
) -> RegexMatch<R.Match>? {
114+
match(content())
115+
}
116+
}

0 commit comments

Comments
 (0)