-
-
Notifications
You must be signed in to change notification settings - Fork 167
[zero-copy] Implement E::Context
and Parser::Config
- parse-time control of parser parameters
#269
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
Conversation
E::Context
and Parser::Config
- parse-time control of parser parametersE::Context
and Parser::Config
- parse-time control of parser parameters
Nice :) Regarding the previous PR... Part of me regrets that the |
src/zero_copy/mod.rs
Outdated
fn configure<F>(self, cfg: F) -> Configure<Self, F> | ||
where | ||
Self: Sized, | ||
F: Fn(Self::Config, &E::Context) -> Self::Config, |
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.
Perhaps Fn(&mut Self::Config, &E::Context)
? LLVM sometimes has trouble optimising moves into references, even when inlining, and I don't see the value of passing by value really, especially if the config is unsized or something.
So I've been experimenting with this a little locally and I've hit a few issues. #[derive(Clone, Debug)]
enum Stmt {
Expr,
Loop(Vec<Stmt>),
}
fn parser<'a>() -> impl Parser<'a, str, Vec<Stmt>> {
let expr = just("expr"); // TODO
let block = recursive(|block| {
let indent = any().filter(|c| *c == ' ')
.repeated()
.configure(|cfg, parent_indent| cfg.exactly(*parent_indent));
let expr_stmt = expr
.then_ignore(text::newline())
.to(Stmt::Expr);
let control_flow = just("loop:")
.then(text::newline())
.ignore_then(block).map(Stmt::Loop);
let stmt = expr_stmt.or(control_flow);
text::whitespace().count()
.then_with_ctx(stmt
.separated_by(indent)
.collect::<Vec<_>>(), |a, b| a)
});
// empty().then_with_ctx(block, |_: (), _: &()| 0)
Parser::<_, _>::then_with_ctx(empty(), block, |_, _| 0)
} First off: this works! let stmts = parser()
.padded()
.then_ignore(end())
.parse(r#"
expr
expr
loop:
expr
loop:
expr
expr
expr
expr
"#);
println!("{:#?}", stmts.output()); yields
See here for the full example. Very cool stuff. However, if I swap the last two lines (they're equivalent) I get the following compilation error:
This seems to happen because the call to I'm not sure how to resolve this. Perhaps it doesn't need solving? Ideally we'd have a Perhaps we should do something like forcing the context of the LHS of |
Forcing the context might work, but that does make issues with nested context-sensitive code. I couldn't do a |
Agreed. Perhaps we should make |
You should now have access to |
Hmmm, actually, I've reversed my stance on |
I can swap it back. That was kind of my idea behind doing it via passing ownership originally, it made the inline code nicer. I can swap it back, it's all of a three line change. |
I've already made the change in CraftSpider#1, feel free to merge it into your branch. |
Oh, one other thing! This effectively replaces |
I wasn't sure whether we wanted to remove it yet, since a lot of parsers aren't yet configurable. OTOH, hopefully most of them will be by the time we release zero-copy, so I'm fine removing it now if you want. |
Considering whether to split configuration into its own subtrait like IterParser - |
I think this seems sensible. I see |
Update: Been busy the past couple days, will get this rebased soon. I'm most of the way through rewriting it into a new trait. |
c3527f5
to
f637c5d
Compare
Ready to merge? |
I would say so, if you think it looks good |
Now with a more readable diff and less intrusive changes, thanks to
ParserExtra
Only two configurations are provided so far - more may be added on-demand, but these two provide enough for useful examples and the most common use-case.