-
Notifications
You must be signed in to change notification settings - Fork 37
Error channels #431
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
Error channels #431
Conversation
So couple of things seem worth noting this morning,
|
Very interesting! I think this PR has a slightly different aim to some of the stuff in #428, so let me see if I can wrap my pea brain around it! It seems to me the main idea here is that the consumer of errors are "remote" (at least, potentially in another thread) so we use That said, reading the code made me realise that perhaps baking in So what I'm now wondering is whether we can break this into perhaps 3 bits:
trait ParseErrorReporting{
fn parse_error(YaccGrammarError) -> Result<(), Box<dyn Error>>;
}
Please feel free to tell me that I have missed something important, as you've thought more deeply about this than I have! |
Yeah, this definitely has a different aim, as this would mostly be under the hood of something like #428 being the mechanism by which errors could be reported promptly before parsing has fully finished. I tend to agree about mpsc::channel being clumsy, overkill and unfortunately producing an error on My biggest gripe about the interface is something like the following,
Because they call to What I would like to do is to try and make Anyhow, I would like to play with that approach before we try to get |
One thing I liked about this approach is that things like nimbleparse can (and actually do currently on the branch) continue using the existing code-path where it returns a I still think we can get this same type of behavior with a trait instead of
I currently have one "nice pretty printer", but it depends on an external library that is partially why I have hesitated to include it in any of these PR's so far (I really appriate how few dependencies grmtools has). I assume at they very least it should have a feature which could be at the very least disabled if not disabled by default, any preference here?
I think the only thing that struck me was the above about nimbleparse not really needing to be affected by this kind of change, (or a similar one using a trait). Another bothersome thing about |
What I'm now wondering is whether we make the trait a type parameter. So, for example, we might have something like: trait ASTErrorReporter {
fn error(...);
fn warning(...);
}
struct ASTBuilder<R: ASTErrorReporter> {
reporter: ASTErrorReporter,
any_error_found: bool,
...
}
impl<R: ASTErrorReporter> for ASTBuilder<R> {
fn blah(...) {
if (...) { self.reporter.error(...); self.any_error_found = true; }
}
fn build(self) -> Result<(), ()> {
if self.any_error_found { Err(()) } else { Ok(()) }
}
} and then we can provide, at least, one impl along the lines of: struct NullASTErrorReporter;
impl ASTErrorReporter for NullASTErrorReport {
fn error(...) { }
fn warning(...) { }
} as well as, perhaps, a simple text error reporter. A neat thing about this general idea is that people can drop in whatever sort of error reporting they might want ( [BTW: I don't know if we need to split apart |
I'll definitely give that a try, I had a lot of trouble trying to do so in |
I'd be fine with starting simple, and doing PRs for where it's easiest, and then trying the big nasty cases later. |
One wrinkle I hadn't considered yet, when switching the I suppose my inclination would be to just leave that API unchanged. With the equivalent for the new type becoming part of the builder chain. Like we could have something like |
Oops, my example didn't do that bit correctly! So that should have been: trait ASTErrorReporter {
fn error(...);
fn warning(...);
}
struct ASTBuilder<R: ASTErrorReporter> {
reporter: ASTErrorReporter,
any_error_found: bool,
...
}
impl<R: ASTErrorReporter> for ASTBuilder<R> {
fn blah(...) {
if (...) { self.reporter.error(...); self.any_error_found = true; }
}
fn build(self) -> Result<AST, ()> {
if self.any_error_found { Err(()) } else { Ok(...) }
}
} On that basis, I'm not quite sure I see what problem there might be with the various |
It really isn't much of a problem, I'm mostly just worring about the ergonomics, due to paradox of choice from an accumulating number of It is unfortunately a little more complex than your example, currently we have something like:
When we sever ownership of errors/warnings of the AST I was imagining we'd have a different structure like
The main thing i'm worried about here is the ergonomics since we are accumulating quite a number of variations of So the main thought was that if we had Sorry if this was a bit long. Edit: I wonder if perhaps renaming what i've been calling |
I agree that this general idea (and |
Alright, so i'm going to do one more of these big branches, just to make sure everything works end-to-end. Then i'll try and cherry-pick PRs from that to hopefully more easily reviewable bits. I probably will not make a PR for the complete branch, but will link to it from the individual PRs so I can rebase it on master as things land. That will give me some confidence we aren't running into any unforeseen issues. Anyhow it seems we can probably close this one for now, and I'll try and get something to look at in the next couple of days. |
Here is my initial exploration, for replacing
Vec<YaccGrammarError>
with error channels in cfgrammar, as was kind of discussed in #428 I figured at least it was worth a shot, because it could be done matching the current ownership structure and giving a decent facsimile of the current API when owning both a send/receive channel.A few things tripped me up, particularly
parse_token
andparse_name
need to returnYaccGrammarError
because sometimes we replace (or drop) the error generated by these functions with a more specific one. particularly in the%expect-unused
code path. I need to more carefully inspect the rest of the code in case there could be more cases such as these.