Skip to content

Commit d34ca0b

Browse files
Removes the restriction on the amount of non-void Parsers that can be used in a Parserbuilder. (#367)
This update removes the need for all Take*n overloads except Take2, and is fully backwards compatible. The parameter pack buildblock relies on a new Take2.Map, which is a tradeoff. On the one hand, we'd prefer to use a Conversion and MapConversion here as the elegant solution. However, consider this mock/theoretical TupleConversion: public struct TupleConversion<each T1, T2>: Conversion { public typealias Input = ((repeat each T1), T2) public typealias Output = (repeat each T1, T2) public func apply( input: ((repeat each T1), T2)) -> (repeat each T1, T2) { let (first, second) = input return (repeat each first, second) } public func unapply( output: (repeat each T1, T2)) -> ((repeat each T1), T2) { guard let tuple = output as? ((repeat each T1), T2) else { fatalError("Could not convert output tuple type") } return tuple } } This would require macOS 14, as it uses parameter packs in generics. This is not fully backwards compatible. I therefore am of the opinion that the tradeoff with introducing Take2.Map is worth it, as this approach maintains backwards compatibility, while only adding a little surface area. See also VariadicTests.swift for passing test. Co-authored-by: Stephen Celis <[email protected]>
1 parent 95080d0 commit d34ca0b

File tree

2 files changed

+95
-311
lines changed

2 files changed

+95
-311
lines changed

Sources/Parsing/Builders/ParserBuilder.swift

Lines changed: 46 additions & 311 deletions
Original file line numberDiff line numberDiff line change
@@ -127,90 +127,28 @@ public enum ParserBuilder<Input> {
127127
where P0.Input == Input, P1.Input == Input {
128128
.init(accumulated, next)
129129
}
130-
130+
131131
@inlinable
132132
public static func buildPartialBlock<P0, P1>(accumulated: P0, next: P1) -> SkipSecond<P0, P1>
133133
where P0.Input == Input, P1.Input == Input {
134134
.init(accumulated, next)
135135
}
136-
137-
@_disfavoredOverload
138-
@inlinable
139-
public static func buildPartialBlock<P0, P1>(accumulated: P0, next: P1) -> Take2<P0, P1>
140-
where P0.Input == Input, P1.Input == Input {
141-
.init(accumulated, next)
142-
}
143-
144-
@_disfavoredOverload
145-
@inlinable
146-
public static func buildPartialBlock<P0, P1, O0, O1>(
147-
accumulated: P0, next: P1
148-
) -> Take3<P0, P1, O0, O1>
149-
where P0.Input == Input, P1.Input == Input {
150-
.init(accumulated, next)
151-
}
152-
153-
@_disfavoredOverload
154-
@inlinable
155-
public static func buildPartialBlock<P0, P1, O0, O1, O2>(
156-
accumulated: P0, next: P1
157-
) -> Take4<P0, P1, O0, O1, O2>
158-
where P0.Input == Input, P1.Input == Input {
159-
.init(accumulated, next)
160-
}
161-
162-
@_disfavoredOverload
163-
@inlinable
164-
public static func buildPartialBlock<P0, P1, O0, O1, O2, O3>(
165-
accumulated: P0, next: P1
166-
) -> Take5<P0, P1, O0, O1, O2, O3>
167-
where P0.Input == Input, P1.Input == Input {
168-
.init(accumulated, next)
169-
}
170-
171-
@_disfavoredOverload
172-
@inlinable
173-
public static func buildPartialBlock<P0, P1, O0, O1, O2, O3, O4>(
174-
accumulated: P0, next: P1
175-
) -> Take6<P0, P1, O0, O1, O2, O3, O4>
176-
where P0.Input == Input, P1.Input == Input {
177-
.init(accumulated, next)
178-
}
179-
180-
@_disfavoredOverload
181-
@inlinable
182-
public static func buildPartialBlock<P0, P1, O0, O1, O2, O3, O4, O5>(
183-
accumulated: P0, next: P1
184-
) -> Take7<P0, P1, O0, O1, O2, O3, O4, O5>
185-
where P0.Input == Input, P1.Input == Input {
186-
.init(accumulated, next)
187-
}
188-
189-
@_disfavoredOverload
190-
@inlinable
191-
public static func buildPartialBlock<P0, P1, O0, O1, O2, O3, O4, O5, O6>(
192-
accumulated: P0, next: P1
193-
) -> Take8<P0, P1, O0, O1, O2, O3, O4, O5, O6>
194-
where P0.Input == Input, P1.Input == Input {
195-
.init(accumulated, next)
196-
}
197-
198-
@_disfavoredOverload
199-
@inlinable
200-
public static func buildPartialBlock<P0, P1, O0, O1, O2, O3, O4, O5, O6, O7>(
201-
accumulated: P0, next: P1
202-
) -> Take9<P0, P1, O0, O1, O2, O3, O4, O5, O6, O7>
203-
where P0.Input == Input, P1.Input == Input {
204-
.init(accumulated, next)
205-
}
206-
136+
207137
@_disfavoredOverload
208-
@inlinable
209-
public static func buildPartialBlock<P0, P1, O0, O1, O2, O3, O4, O5, O6, O7, O8>(
210-
accumulated: P0, next: P1
211-
) -> Take10<P0, P1, O0, O1, O2, O3, O4, O5, O6, O7, O8>
212-
where P0.Input == Input, P1.Input == Input {
213-
.init(accumulated, next)
138+
public static func buildPartialBlock<P0: Parser, P1: Parser, each O1, O2>(
139+
accumulated: P0,
140+
next: P1
141+
) -> Take2<P0, P1>.Map<(repeat each O1, O2)>
142+
where
143+
P0.Input == Input,
144+
P1.Input == Input,
145+
P0.Output == (repeat each O1),
146+
P1.Output == O2
147+
{
148+
Take2(accumulated, next)
149+
.map { tuple, next in
150+
(repeat each tuple, next)
151+
}
214152
}
215153

216154
public struct SkipFirst<P0: Parser, P1: Parser>: Parser
@@ -268,152 +206,6 @@ public enum ParserBuilder<Input> {
268206
} catch { throw ParsingError.wrap(error, at: input) }
269207
}
270208
}
271-
272-
public struct Take3<P0: Parser, P1: Parser, O0, O1>: Parser
273-
where P0.Input == P1.Input, P0.Output == (O0, O1) {
274-
@usableFromInline let p0: P0, p1: P1
275-
276-
@usableFromInline init(_ p0: P0, _ p1: P1) {
277-
self.p0 = p0
278-
self.p1 = p1
279-
}
280-
281-
@inlinable public func parse(_ input: inout P0.Input) rethrows -> (O0, O1, P1.Output) {
282-
do {
283-
let (o0, o1) = try self.p0.parse(&input)
284-
return try (o0, o1, self.p1.parse(&input))
285-
} catch { throw ParsingError.wrap(error, at: input) }
286-
}
287-
}
288-
289-
public struct Take4<P0: Parser, P1: Parser, O0, O1, O2>: Parser
290-
where P0.Input == P1.Input, P0.Output == (O0, O1, O2) {
291-
@usableFromInline let p0: P0, p1: P1
292-
293-
@usableFromInline init(_ p0: P0, _ p1: P1) {
294-
self.p0 = p0
295-
self.p1 = p1
296-
}
297-
298-
@inlinable public func parse(_ input: inout P0.Input) rethrows -> (O0, O1, O2, P1.Output) {
299-
do {
300-
let (o0, o1, o2) = try self.p0.parse(&input)
301-
return try (o0, o1, o2, self.p1.parse(&input))
302-
} catch { throw ParsingError.wrap(error, at: input) }
303-
}
304-
}
305-
306-
public struct Take5<P0: Parser, P1: Parser, O0, O1, O2, O3>: Parser
307-
where P0.Input == P1.Input, P0.Output == (O0, O1, O2, O3) {
308-
@usableFromInline let p0: P0, p1: P1
309-
310-
@usableFromInline init(_ p0: P0, _ p1: P1) {
311-
self.p0 = p0
312-
self.p1 = p1
313-
}
314-
315-
@inlinable public func parse(_ input: inout P0.Input) rethrows -> (O0, O1, O2, O3, P1.Output) {
316-
do {
317-
let (o0, o1, o2, o3) = try self.p0.parse(&input)
318-
return try (o0, o1, o2, o3, self.p1.parse(&input))
319-
} catch { throw ParsingError.wrap(error, at: input) }
320-
}
321-
}
322-
323-
public struct Take6<P0: Parser, P1: Parser, O0, O1, O2, O3, O4>: Parser
324-
where P0.Input == P1.Input, P0.Output == (O0, O1, O2, O3, O4) {
325-
@usableFromInline let p0: P0, p1: P1
326-
327-
@usableFromInline init(_ p0: P0, _ p1: P1) {
328-
self.p0 = p0
329-
self.p1 = p1
330-
}
331-
332-
@inlinable public func parse(_ input: inout P0.Input) rethrows -> (
333-
O0, O1, O2, O3, O4, P1.Output
334-
) {
335-
do {
336-
let (o0, o1, o2, o3, o4) = try self.p0.parse(&input)
337-
return try (o0, o1, o2, o3, o4, self.p1.parse(&input))
338-
} catch { throw ParsingError.wrap(error, at: input) }
339-
}
340-
}
341-
342-
public struct Take7<P0: Parser, P1: Parser, O0, O1, O2, O3, O4, O5>: Parser
343-
where P0.Input == P1.Input, P0.Output == (O0, O1, O2, O3, O4, O5) {
344-
@usableFromInline let p0: P0, p1: P1
345-
346-
@usableFromInline init(_ p0: P0, _ p1: P1) {
347-
self.p0 = p0
348-
self.p1 = p1
349-
}
350-
351-
@inlinable public func parse(_ input: inout P0.Input) rethrows -> (
352-
O0, O1, O2, O3, O4, O5, P1.Output
353-
) {
354-
do {
355-
let (o0, o1, o2, o3, o4, o5) = try self.p0.parse(&input)
356-
return try (o0, o1, o2, o3, o4, o5, self.p1.parse(&input))
357-
} catch { throw ParsingError.wrap(error, at: input) }
358-
}
359-
}
360-
361-
public struct Take8<P0: Parser, P1: Parser, O0, O1, O2, O3, O4, O5, O6>: Parser
362-
where P0.Input == P1.Input, P0.Output == (O0, O1, O2, O3, O4, O5, O6) {
363-
@usableFromInline let p0: P0, p1: P1
364-
365-
@usableFromInline init(_ p0: P0, _ p1: P1) {
366-
self.p0 = p0
367-
self.p1 = p1
368-
}
369-
370-
@inlinable public func parse(_ input: inout P0.Input) rethrows -> (
371-
O0, O1, O2, O3, O4, O5, O6, P1.Output
372-
) {
373-
do {
374-
let (o0, o1, o2, o3, o4, o5, o6) = try self.p0.parse(&input)
375-
return try (o0, o1, o2, o3, o4, o5, o6, self.p1.parse(&input))
376-
} catch { throw ParsingError.wrap(error, at: input) }
377-
}
378-
}
379-
380-
public struct Take9<P0: Parser, P1: Parser, O0, O1, O2, O3, O4, O5, O6, O7>: Parser
381-
where P0.Input == P1.Input, P0.Output == (O0, O1, O2, O3, O4, O5, O6, O7) {
382-
@usableFromInline let p0: P0, p1: P1
383-
384-
@usableFromInline init(_ p0: P0, _ p1: P1) {
385-
self.p0 = p0
386-
self.p1 = p1
387-
}
388-
389-
@inlinable public func parse(_ input: inout P0.Input) rethrows -> (
390-
O0, O1, O2, O3, O4, O5, O6, O7, P1.Output
391-
) {
392-
do {
393-
let (o0, o1, o2, o3, o4, o5, o6, o7) = try self.p0.parse(&input)
394-
return try (o0, o1, o2, o3, o4, o5, o6, o7, self.p1.parse(&input))
395-
} catch { throw ParsingError.wrap(error, at: input) }
396-
}
397-
}
398-
399-
public struct Take10<P0: Parser, P1: Parser, O0, O1, O2, O3, O4, O5, O6, O7, O8>: Parser
400-
where P0.Input == P1.Input, P0.Output == (O0, O1, O2, O3, O4, O5, O6, O7, O8) {
401-
@usableFromInline let p0: P0, p1: P1
402-
403-
@usableFromInline init(_ p0: P0, _ p1: P1) {
404-
self.p0 = p0
405-
self.p1 = p1
406-
}
407-
408-
@inlinable public func parse(_ input: inout P0.Input) rethrows -> (
409-
O0, O1, O2, O3, O4, O5, O6, O7, O8, P1.Output
410-
) {
411-
do {
412-
let (o0, o1, o2, o3, o4, o5, o6, o7, o8) = try self.p0.parse(&input)
413-
return try (o0, o1, o2, o3, o4, o5, o6, o7, o8, self.p1.parse(&input))
414-
} catch { throw ParsingError.wrap(error, at: input) }
415-
}
416-
}
417209
}
418210

419211
extension ParserBuilder.SkipFirst: ParserPrinter where P0: ParserPrinter, P1: ParserPrinter {
@@ -440,93 +232,6 @@ extension ParserBuilder.Take2: ParserPrinter where P0: ParserPrinter, P1: Parser
440232
}
441233
}
442234

443-
extension ParserBuilder.Take3: ParserPrinter where P0: ParserPrinter, P1: ParserPrinter {
444-
@inlinable
445-
public func print(_ output: (O0, O1, P1.Output), into input: inout P0.Input) rethrows {
446-
try self.p1.print(output.2, into: &input)
447-
try self.p0.print((output.0, output.1), into: &input)
448-
}
449-
}
450-
451-
extension ParserBuilder.Take4: ParserPrinter where P0: ParserPrinter, P1: ParserPrinter {
452-
@inlinable
453-
public func print(_ output: (O0, O1, O2, P1.Output), into input: inout P0.Input) rethrows {
454-
try self.p1.print(output.3, into: &input)
455-
try self.p0.print((output.0, output.1, output.2), into: &input)
456-
}
457-
}
458-
459-
extension ParserBuilder.Take5: ParserPrinter where P0: ParserPrinter, P1: ParserPrinter {
460-
@inlinable
461-
public func print(_ output: (O0, O1, O2, O3, P1.Output), into input: inout P0.Input) rethrows {
462-
try self.p1.print(output.4, into: &input)
463-
try self.p0.print((output.0, output.1, output.2, output.3), into: &input)
464-
}
465-
}
466-
467-
extension ParserBuilder.Take6: ParserPrinter where P0: ParserPrinter, P1: ParserPrinter {
468-
@inlinable
469-
public func print(
470-
_ output: (O0, O1, O2, O3, O4, P1.Output),
471-
into input: inout P0.Input
472-
) rethrows {
473-
try self.p1.print(output.5, into: &input)
474-
try self.p0.print((output.0, output.1, output.2, output.3, output.4), into: &input)
475-
}
476-
}
477-
478-
extension ParserBuilder.Take7: ParserPrinter where P0: ParserPrinter, P1: ParserPrinter {
479-
@inlinable
480-
public func print(
481-
_ output: (O0, O1, O2, O3, O4, O5, P1.Output),
482-
into input: inout P0.Input
483-
) rethrows {
484-
try self.p1.print(output.6, into: &input)
485-
try self.p0.print((output.0, output.1, output.2, output.3, output.4, output.5), into: &input)
486-
}
487-
}
488-
489-
extension ParserBuilder.Take8: ParserPrinter where P0: ParserPrinter, P1: ParserPrinter {
490-
@inlinable
491-
public func print(
492-
_ output: (O0, O1, O2, O3, O4, O5, O6, P1.Output),
493-
into input: inout P0.Input
494-
) rethrows {
495-
try self.p1.print(output.7, into: &input)
496-
try self.p0.print(
497-
(output.0, output.1, output.2, output.3, output.4, output.5, output.6),
498-
into: &input
499-
)
500-
}
501-
}
502-
503-
extension ParserBuilder.Take9: ParserPrinter where P0: ParserPrinter, P1: ParserPrinter {
504-
@inlinable
505-
public func print(
506-
_ output: (O0, O1, O2, O3, O4, O5, O6, O7, P1.Output),
507-
into input: inout P0.Input
508-
) rethrows {
509-
try self.p1.print(output.8, into: &input)
510-
try self.p0.print(
511-
(output.0, output.1, output.2, output.3, output.4, output.5, output.6, output.7),
512-
into: &input
513-
)
514-
}
515-
}
516-
517-
extension ParserBuilder.Take10: ParserPrinter where P0: ParserPrinter, P1: ParserPrinter {
518-
@inlinable
519-
public func print(
520-
_ output: (O0, O1, O2, O3, O4, O5, O6, O7, O8, P1.Output),
521-
into input: inout P0.Input
522-
) rethrows {
523-
try self.p1.print(output.9, into: &input)
524-
try self.p0.print(
525-
(output.0, output.1, output.2, output.3, output.4, output.5, output.6, output.7, output.8),
526-
into: &input
527-
)
528-
}
529-
}
530235

531236
extension ParserBuilder where Input == Substring {
532237
@_disfavoredOverload
@@ -546,3 +251,33 @@ extension ParserBuilder where Input == Substring.UTF8View {
546251
expression
547252
}
548253
}
254+
255+
extension ParserBuilder.Take2 {
256+
public struct Map<NewOutput>: Parser where P0.Input == P1.Input {
257+
let upstream: ParserBuilder.Take2<P0, P1>
258+
let transform: (P0.Output, P1.Output) -> NewOutput
259+
260+
public func parse(_ input: inout P0.Input) throws -> NewOutput {
261+
let (first, second) = try upstream.parse(&input)
262+
return transform(first, second)
263+
}
264+
}
265+
266+
public func map<NewOutput>(_ transform: @escaping (P0.Output, P1.Output) -> NewOutput) -> Map<NewOutput> {
267+
Map(upstream: self, transform: transform)
268+
}
269+
}
270+
271+
extension ParserBuilder.Take2.Map: ParserPrinter
272+
where P0: ParserPrinter, P1: ParserPrinter {
273+
public func print(_ output: NewOutput, into input: inout P0.Input) throws {
274+
guard let tuple = output as? (P0.Output, P1.Output) else {
275+
throw ParsingError.failed(
276+
summary: "Could not convert output to required tuple type",
277+
from: output,
278+
to: input
279+
)
280+
}
281+
try upstream.print(tuple, into: &input)
282+
}
283+
}

0 commit comments

Comments
 (0)