[DISCARDED] RFC: WIP: Several improvements in error reporting #102
Conversation
|
The tests are passing in this branch, but the work is not finished yet. I would like to collect feedback before I rebase and finalize all of the |
9871462 to
87f9f68
Compare
|
The commit is rebased now against the latest commits made to the master branch, and the tests are 99% passing (see the WIP about There are a few places where I am slightly reverting the idea of this commit: db503c9. This is only due to the fact that my diagnostics implementation had been implemented with the previous design in mind, before these commits appeared. At the same time, I am still not convinced that the newly introduced behavior of the Optionals would not confuse the users because it is already quite confusing to myself. Having this said, I totally support the idea of Arpeggio reporting on the "pathological" grammar cases like you explained it in your comments. I have left several Aside from the discussion points, please follow how much better / more precise the reporting became in many (most?) cases. The previous implementation of |
62c2010 to
580bb81
Compare
If a branch in ordered choice has a potentially non-consuming successful alternative (Optional, ZeroOrMore, Not, And), it will succeed if alternative succeeds and thus will not try further choices.
470a88a to
84ed1fc
Compare
84ed1fc to
1d79445
Compare
1d79445 to
9cb939d
Compare
This patch is more advanced compared to textX#100 The NoMatch class is made smarter and tracks the exact match errors. With this design, reporting an error translates to printing the diagnostics of all failed subexpressions of a failed expressions. For example, for `Sequence`, the `SequenceNoMatch` class collects the failed expression as well as all previously matched (but failed) `Optional` expressions. The naming of `*NoMatch` certainly introduces some redundancy in the class names, however, without this measure I had hard time visualizing the internal structure of the failed expression to be printed. Open question: - Is this desirable that in case of ordered choices, we could print not only the winning match but all matches that are equally possible, as in this example: ``` assert ( "Expected '4' at position (1, 15)" " or " "'five' at position (1, 20)" in str(e.value) ) ``` The advantage of this approach would be that a user sees all alternatives that are possible in cases like this. The cost: the implementation has to control whether several `at position` strings have to be presented instead of a single `at position` at the end of the inspection message.
9cb939d to
2b442b4
Compare
|
@igordejanovic, I have done testing of my branch and came to the following conclusions:
At first, I got scared, and then I thought that this feature is something that is extremely nice to have because it educates the users about how my grammar can be used. Sometimes, the weakly failed expressions are not sorted according to their position, this is something that I could work on next. Very often, several failed expressions are reported on the same line, it should be trivial to cluster them to be on the same line.
It would be great if you could try this branch yourself. I am curious to know if you see a good potential in this to be developed further. P.S. Given this increased visibility into the weakly failed rules, I also pay more attention to when I see more obscure positions reported about the available options. In particular, there are cases, when I have After some tinkering with formatting in this branch (it is on top of this PR), I got this: |
|
Here are a few more observations: I tested SDoc documents independently with and without this branch, and it looks like the performance degrades quite noticeably. I still don't have a good number, but it can be 25%+ which is a no-go for the original strength of PEG of being very fast. I think most of the time is spent on constructing composite With this in mind, I tried to imagine how this branch would work under a config option, such as
I have spent quite some time working on this feature and I really like it, but I don't see an easy way to combine the performance feature and the level of detail given by this branch. With this said, please don't feel forced to integrate it at all cost just because I am an active user. I myself certainly want a solution that does not degrade the nominal performance of Arpeggio. I very interested in both having Arpeggio to work as fast as possible and at the same time having an option to make it give more detailed diagnostics like what this branch can do. I would be curious to know if:
|
|
@stanislaw I did a benchmark test with textX with both current Arpeggio master branch and this PR. The results are quite discouraging. This branch is about 2x slower than the current master. Also, memory consumption is about 2x increased. Definitely a no-go. I've been thinking about this detailed report and I must say that while it looked promising at first I'm not sure anymore that it would be easy to grasp for the end-user and that it would bring any benefit. For the developer it always give more info running the parser in debug mode. We could investigate possibility of keeping a limited backtrace of weak failures. While that could make memory usage profile better, still I don't expect that it would make speed degradation any better. Also, trying to keep both I understand that you have spent quite some time investigating this approach and I thank you for that. The parsing is not easy. I have also been down that rabbit hole myself of trying to change the design in the hope of getting better at some aspect but the constraint of keeping everything both performant and simple was often got in my way making me retreat. I think that we should also investigate extending I don't want to discourage you from continuing with this direction but I don't see at the moment in what direction to go to improve on the current master. |
|
I literally agree with every paragraph and sentence from your reply. I didn't realize, I had access to the same performance tools that you have. I have run While I consider this branch to be a failure, I certainly learned a couple of things about what Arpeggio does, and before we come back to What if we would introduce something similar to what If the circular buffer approach was followed, another building block could be an object pool implementation (this is just what googles first: https://github.com/T-baby/pondpond). If the NoMatch objects from the circular buffer are recycled back into the object pool, you don't have to endlessly create NoMatch objects over and over again. I could imagine that this could give you a few extra bits of performance even within the current master branch. Do you actually have an idea what is an average allocation ratio for an arbitrary grammar/input? Do they happen often with I was actually spending some time playing around with a broader diagnostics of this branch when working against StrictDoc documents, and I am quite convinced that the advanced diagnostics output could be optimized/presented visually in a form of a tutorial-like experience as you work against a given grammar. Let me know if the above makes sense anyhow. I am very much ready to close this branch and move on but I think there is some opportunity for more precise diagnostics/reporting that I want to double-check before giving up. |
Having a research background I would definitely not call this a failure. You have investigated a new approach and we all learned something new. In textX perf tests there is also a profiling report in the form of pdf. Look at the benchmark branch. This can give you a clue where the time is spent the most. I guess having a |
I don't have figures. We could find out by introducing counter in |
Definitely yes! I would be ready to continue digging, if a promising direction was found 😄
I am taking a note and will take a look.
I have tried this already in this branch. The circular buffer is right in I have hit another problem with this approach, though. If everything is written to the buffer, then during the report time, also the exceptions that were eventually matched on a higher level are printed. A simple example: This test fails because the successful 'a' alternative from the ordered choice is printed as well. I say that 'a' is "successful" because 'b' is successful and therefore the whole parent Which leads me to a question that either: a) This circular buffer has to be "garbage-collected" from the successfully failed rules when they were successful because of their parent expression. I have tried this for the Let me know if you see anything promising in this direction. After all, I feel like I am stepping into the parsers territory with almost no theoretical background, so I am moving using try/error, not using educated guesses 😄 |
|
Closing this in favor of the new one #114. |
This patch is more advanced compared to #100
WIP checklist:
weakly_failed_rules__.# Unsuccessful match of the whole PE - full backtracking.The NoMatch class is made smarter and tracks the exact match errors. With this design, reporting an error translates to printing the diagnostics of all failed subexpressions of a failed expression.
For example, for
Sequence, theSequenceNoMatchclass collects the failed expression as well as all previously matched (but failed)Optionalexpressions.The naming of
*NoMatchcertainly introduces some redundancy in the class names, however, without this measure I had hard time visualizing the internal structure of the failed expression to be printed.Open question:
The advantage of this approach would be that a user sees all alternatives that are possible in cases like this. The cost: the implementation has to control whether several
at positionstrings have to be presented instead of a singleat positionat the end of the inspection message.Code review checklist
CHANGELOG.md, no needto update for typo fixes and such).