-
I'm leaving the initial question here for posterity, but I've rubberduck'd sufficiently into a more precise question further down below: #373 (comment) Hey folks! I've got a relatively simple parser here, with some broken down sub-parsers. I'm going to omit the sub-parsers since they seem to be behaving fine, but let me know if seeing them would be helpful. Here's the domain type and the parser: public enum SingleQuery: Equatable {
case axisQuery(AxisQuery)
case nameQuery(NameQuery)
}
struct SingleQueryParser: ParserPrinter {
var body: some ParserPrinter<Substring, SingleQuery> {
OneOf {
AxisQueryParser().map(.case(SingleQuery.axisQuery))
NameQueryParser().map(.case(SingleQuery.nameQuery))
}
}
} I wrote the following test to check if printing is happening correctly using the snapshot library: @Test("Single query prints name correctly")
func singleQuery_printsNameCorrectly() async throws {
let parser = SingleQueryParser()
let input = SingleQuery.nameQuery(.init(searchTerm: .quoted(text: "Hello there")))
assertInlineSnapshot(of: try parser.print(input), as: .description)
} Doing so gives me the following error:
Here's an image: I was under the impression that |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments
-
Okay looks like the struct SingleQueryParser: ParserPrinter {
var body: some ParserPrinter<Substring, SingleQuery> {
NameQueryParser().map(.case(SingleQuery.nameQuery))
}
} And I still get an error, but this time they are just the |
Beta Was this translation helpful? Give feedback.
-
Looks like these errors are coming from this extension in Consumed.swift: extension Consumed: ParserPrinter where Upstream.Input: PrependableCollection {
@inlinable
public func print(_ output: Upstream.Input, into input: inout Upstream.Input) rethrows {
do {
_ = try self.upstream.parse(output)
input.prepend(contentsOf: output)
} catch {
throw PrintingError.failed(summary: "TODO", input: input)
}
}
} I do use import Parsing
public enum SearchTerm: Equatable {
case quoted(text: Substring)
case unquoted(text: Substring)
}
// MARK: - Conversion
struct SearchTermConversion: Conversion {
let isQuoted: Bool
func apply(_ input: Substring) throws -> SearchTerm {
if isQuoted {
.quoted(text: input)
} else {
.unquoted(text: input)
}
}
func unapply(_ output: SearchTerm) throws -> Substring {
switch output {
case let .quoted(substring):
"\"\(substring)\""
case let .unquoted(substring):
substring
}
}
}
// MARK: - Parsers
struct SearchTermParser: ParserPrinter {
var body: some ParserPrinter<Substring, SearchTerm> {
OneOf {
QuotedSearchTermParser()
UnquotedSearchTermParser()
}
}
}
struct QuotedSearchTermParser: ParserPrinter {
var body: some ParserPrinter<Substring, SearchTerm> {
Parse(SearchTermConversion(isQuoted: true)) {
"\""
Consumed {
Prefix { $0 != "\"" }
}
"\""
}
}
}
struct UnquotedSearchTermParser: ParserPrinter {
var body: some ParserPrinter<Substring, SearchTerm> {
Parse(SearchTermConversion(isQuoted: false)) {
Consumed {
Prefix { !$0.isWhitespace }
}
}
}
} I'm going to try alternatives to the |
Beta Was this translation helpful? Give feedback.
-
Ok I've narrowed down the issue a lot, to the point where I've renamed this discussion. I have the following conversion and parser: struct SearchTermConversion: Conversion {
let isQuoted: Bool
func apply(_ input: Substring) throws -> SearchTerm {
if isQuoted {
.quoted(text: input)
} else {
.unquoted(text: input)
}
}
func unapply(_ output: SearchTerm) throws -> Substring {
switch output {
case let .quoted(substring):
"\"\(substring)\""
case let .unquoted(substring):
substring
}
}
}
struct QuotedSearchTermParser: ParserPrinter {
var body: some ParserPrinter<Substring, SearchTerm> {
Parse(SearchTermConversion(isQuoted: true)) {
"\""
Prefix { $0 != "\"" }
"\""
}
}
} I'm getting an error saying that the printed value doesn't satisfy the predicate, which is technically true, but I'm not sure how to model this such that that's not the case. Basically, the printed string contains quotes (e.g. |
Beta Was this translation helpful? Give feedback.
-
Ok, finally a solution: Since I have a custom conversion adding in quotes to the printed value, I need to symmetrically remove the quotes inside the conversion, rather than omitting them entirely from the parser. Here's the code that fixed everything: First we surround the entire contents of the parser with struct QuotedSearchTermParser: ParserPrinter {
var body: some ParserPrinter<Substring, SearchTerm> {
Parse(SearchTermConversion(isQuoted: true)) {
// NEW
Consumed {
"\""
Prefix { $0 != "\"" }
"\""
}
}
}
} Then we update the struct SearchTermConversion: Conversion {
enum Error: Swift.Error {
case quotedStringIsMissingQuotes
}
let isQuoted: Bool
func apply(_ input: Substring) throws -> SearchTerm {
if isQuoted {
// NEW
guard input.first == "\"", input.last == "\"", input.count > 1 else {
throw Error.quotedStringIsMissingQuotes
}
let startIndex = input.index(after: input.startIndex)
let endIndex = input.index(before: input.endIndex)
return .quoted(text: input[startIndex..<endIndex]);
} else {
return .unquoted(text: input)
}
}
func unapply(_ output: SearchTerm) throws -> Substring {
switch output {
case let .quoted(substring):
"\"\(substring)\""
case let .unquoted(substring):
substring
}
}
} 🦆 Rubber-ducking is busted, people. |
Beta Was this translation helpful? Give feedback.
Ok, finally a solution:
Since I have a custom conversion adding in quotes to the printed value, I need to symmetrically remove the quotes inside the conversion, rather than omitting them entirely from the parser. Here's the code that fixed everything:
First we surround the entire contents of the parser with
Consumed
so the void-returning string literal parsers are now included in the substring passed to the conversion:Then we update …