- 
                Notifications
    You must be signed in to change notification settings 
- Fork 85
Printer prepending instead of appending #145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Printer prepending instead of appending #145
Conversation
…'t been released publicly yet.
Consequentially, all parsers that compose multiple parsers work backwards through provided parsers, and the `input` is built up from the back to the front. This allows print to check that the output is correct for cases like `Rest`, `Prefix`, `Not`, and `Peek`.
| A couple of notes: Currently there is one failing test:  I've left it in because I haven't been able to find a way to have a  I'm not sure that it's possible to actually  As such, I'm going to revive my pitch for  I haven't checked it in currently, but am happy to do so. | 
| Hey @randomeizer, Stephen is traveling right now so may not have time to reply, but we discussed this morning and what you have found is definitely interesting! 🙂 The reversal of zip mimics how  swift-parsing/Sources/Parsing/Builders/Variadics.swift Lines 9401 to 9410 in 1ba3e9c 
 So it definitely seems like a viable thing to do. And further, as you have noted, by reversing the order printers get an opportunity to better see the full picture of what is being printed in order to implement its logic, just like parsers. There are even some existing parser/printers that could take advantage of this, like  extension End: Printer {
  @inlinable
  public func print(_ output: Void, to input: inout Input) throws {
    guard input.isEmpty
    else { throw PrintingError() }
  }
}Which would making printing non-sensical things like this fail even though currently it passes on printer-throws-2: ParsePrint { "Hello"; End(); "World" }.print(())So, suffice to say, we've got some more thinking to do! We're going to play around with this for a bit more and see where it takes us. Thanks for brining it up! | 
| Just wanted to relay a few discussion points @stephencelis and I had this morning about this PR. 
 | 
| Yeah, the prepending nature of  The performance penalty is unfortunate. It's a pity we can't actually append then just flip the order at the end of the print, once. I suspect it would be a faster operation. Might be possible if  | 
Added related tests.
| If  | 
| Regarding prepending, it might be faster to create a new  | 
| 
 Yeah I think that's the way to go. Creating an empty value and then appending in reverse order is only slightly slower than just appending. Also, my benchmark above is not great because  | 
They now append into a copy of themselves, then append the `input`.
| I've just pushed an update to  The implementations of  | 
| Yeah, I think most printer implementations won't have to think about this detail because they will usually write their conformances against  | 
Makes it clearer under what circumstances it will fail without backtracking.
Also updated documentation about backtracking in general.
Which can be both parsed and printed.
Added notes about why it doesn't throw an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great finds! Thanks! We're going to merge this into the main printer branch now.
* wip * don't backtrack * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * rank one of errors * rank errors by most processed * nested * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * from * wip * wip * wip * Update benches * wip * idiomatic * wip * wip * wip * truncate * wip * wip * wip * wip * clean up * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * Some docs and update tests to use public conversion * removed testable imports * lots of docs * wip * wip * wip * many terminator failure * wip * add loop error * force MapConversion to work only on printers * bye bye exactly * wip * wip * Added reversion to original if any parsers in `Zip` variations throw an error (#107) * Added reversion to original if any parsers in `Zip` variations throw an error. * Updated ParserBuilderTests to check correct consumption of the input * wip * fix * wip * wip * wip * wip * wip * wip * fix * wip * wip * wip * wip * Bump package tools version * wip * fix * backtrack printing * wip * wip * wip * wip * wip * New VoidMap parser and updated race parser. * wip * pullback * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * docs * wip * wip * wip * wip * wip * wip * wiop * print tests for PrefixUpTo/Through * Printer prepending instead of appending (#145) * Pointing `swift-custom-dump` to the "main" branch, since `0.4.0` hasn't been released publicly yet. * Switched printing to `prepend` rather than `append` Consequentially, all parsers that compose multiple parsers work backwards through provided parsers, and the `input` is built up from the back to the front. This allows print to check that the output is correct for cases like `Rest`, `Prefix`, `Not`, and `Peek`. * Added `Many` tests, fixed terminator bug * Whitespace cleanup * Fixed typo in test name. * Updated `End` to check input when printing. Added related tests. * Switched `Literal` printing to append rather than insert They now append into a copy of themselves, then append the `input`. * Updated `PrependableCollection` to use `append` internally * Improved error output for OneOfMany * Adds backtracking to `Optionally` * Added unit test to check backtracking * Updated the `testBacktracking` case Makes it clearer under what circumstances it will fail without backtracking. * Added backtracking to Optionally Also updated documentation about backtracking in general. * Removed incorrectly merged test case. * Added `Expect` Which can be both parsed and printed. * Made the unexpected `Peek` success a passing test Added notes about why it doesn't throw an error. * wip * wip * wip * wip * wip * Update README.md Co-authored-by: Brandon Williams <[email protected]> * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * fixes Co-authored-by: Stephen Celis <[email protected]> Co-authored-by: Stephen Celis <[email protected]> Co-authored-by: Brandon Williams <[email protected]> * wip * wip * Updates Optionally to throw any internal `wrapped.print(...)` error (#167) * Pointing `swift-custom-dump` to the "main" branch, since `0.4.0` hasn't been released publicly yet. * Made Optionally fail if the wrapped parser fails Added test cases for printing, and example of failing an invalid print. * Remove `.map` overload on Always * wip * wip * Make Rest.print fail on empty output. * roundtripping doc * wip * struct conversion docs * rename .struct to .memberwise * fixes * lots of docs * docs * wip * wip * Revert "wip" This reverts commit cde658d. * Printer -> ParserPrinter * wip * wip * wip * wip * wip * wip * wip * basic errors * wip * wip * fix * Simplify `Consumed` * wip * wip * wip * decumulator * wip * wip * wip * wip * wip * wip * clean up * wip * wip * wip * wip * wip * wip * fix * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * fix docc warnings * wip * wip * wip * wip * wip * wip * wip * fix Co-authored-by: Stephen Celis <[email protected]> Co-authored-by: David Peterson <[email protected]> Co-authored-by: Stephen Celis <[email protected]>


This is an implementation of the ideas posted in #144.
The basic concept with this PR is to reverse the building order of the final
inputwhen printing.In the current implementation, the
inputis built up from the beginning to the end of the parser chain. Each subsequent parser appends its value to the end of theinput.The chief consequence of this is that you can build
Parsers which throw an error when callingparse, but will not throw an error when callingprint. For example:This is obviously a buggy parser, but the fact that they are not commutable is a concern. Both should fail the same way.
Another case is
Not, which checks the currentinputto see if it matches, if so, throws an error. Otherwise parsing continues. Either way, no input is consumed. Here's an example:Currently,
Notwould have to be implemented like so:The solution is to build up the
inputin reverse, so that eachprintcan check that the same expectations for theparsestill hold.This has two main changes in how
print(_:to:)works.input.inputwill contain all subsequentprintvalues, and can be checked for correctness.To fix our
uncommentedLineParser, we need to tweakParsers.ZipVO:It now prints
p1first, thenp0.Now, the
Prefixwill get printed into theinputbefore theNotreceives it, and we can do this:Now, this line will also fail, same as when it is parsed:
As a side-effect of this change, the following is now also possible:
This was not possible with the append approach, indicating that prepending is necessary for true commutability.
Thank you for attending my Ted Talk.