-
I have the following code that is similar to your calculator in the tutorial: #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum ListEnvelopesFilter {
And(Box<ListEnvelopesFilter>, Box<ListEnvelopesFilter>),
Or(Box<ListEnvelopesFilter>, Box<ListEnvelopesFilter>),
Not(Box<ListEnvelopesFilter>),
Folder(String),
Before(DateTime<Local>),
After(DateTime<Local>),
From(String),
To(String),
Subject(String),
Body(String),
Keyword(String),
None,
}
pub type ParserError<'a> = extra::Err<Rich<'a, char>>;
pub(crate) fn filter<'a>() -> impl Parser<'a, &'a str, ListEnvelopesFilter, ParserError<'a>> + Clone {
recursive(|filter| {
let filter = choice((
filter.delimited_by(just(LPARENS), just(RPARENS)),
condition(),
))
.padded();
let not = just("not").padded().repeated().foldr(filter, |_, filter| {
ListEnvelopesFilter::Not(Box::new(filter))
});
let and = not.clone().foldl(
just("and").padded().ignored().then(not).repeated(),
|left, (_, right)| ListEnvelopesFilter::And(Box::new(left), Box::new(right)),
);
let or = and.clone().foldl(
just("or").padded().ignored().then(and).repeated(),
|left, (_, right)| ListEnvelopesFilter::Or(Box::new(left), Box::new(right)),
);
or
})
}
fn condition<'a>() -> impl Parser<'a, &'a str, ListEnvelopesFilter, ParserError<'a>> + Clone {
choice((
from(),
to(),
subject(),
body(),
keyword(),
before(),
after(),
))
}
// All parsers are similar, so I post only one:
fn from<'a>() -> impl Parser<'a, &'a str, ListEnvelopesFilter, ParserError<'a>> + Clone {
just("from")
.padded()
.ignore_then(val())
.map(ListEnvelopesFilter::From)
} No matter which
I am using the |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 13 replies
-
Could you give some more information about where you're adding |
Beta Was this translation helpful? Give feedback.
-
Here a small version of the code, it still does not use the label even without the recursive: #[test]
fn repro() {
use chumsky::prelude::*;
#[derive(Debug, Eq, PartialEq)]
enum Filter {
From(String),
To(String),
Subject(String),
Body(String),
None,
}
fn filter<'a>() -> impl Parser<'a, &'a str, Filter, extra::Err<Rich<'a, char>>> {
choice((
just("from")
.labelled("From1")
.ignore_then(text::ident().labelled("From2"))
.map(|from: &str| Filter::From(from.to_string()))
.labelled("From3"),
just("to")
.ignore_then(text::ident())
.map(|to: &str| Filter::To(to.to_string())),
just("subject")
.ignore_then(text::ident())
.map(|subject: &str| Filter::Subject(subject.to_string())),
just("body")
.ignore_then(text::ident())
.map(|body: &str| Filter::Body(body.to_string())),
))
.padded()
}
assert_eq!(filter().parse("wrong").into_result(), Ok(Filter::None))
}
|
Beta Was this translation helpful? Give feedback.
-
Probably soon, I think there are enough changes for it to be worth it!
Awesome!
I'd really like to finally push for 1.0 stable, but there's still a
fairly substantial todo list :(
Then I wish you good luck, my tool is also accumulating betas without
reaching the v1, frustrating!
|
Beta Was this translation helpful? Give feedback.
Thanks for that information. I've found the problem with
text::keyword
(it was actually a subtle issue intry_map
, of all things!), d93e12a contains that fix.Regarding
text::whitespace
: that behaviour is actually expected (although I agree that it's suboptimal). Resolving it will require a slightly larger rework of the way error handling works. However, I've been doing a lot of thinking about that recently and I've come up with a design that I believe should entirely resolve these problems: I'll probably try implementing it over the next few days.