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
How to make choice prefer the first parser? #181
Comments
The problem here is that You probably want to use |
Oh ok I see - but that's a problem. If a |
Do you want a |
Yes, exactly. Like |
|
Ok so I tried this instead of fn group<T>(
begin: &'static str,
end: &'static str,
parser: impl Parser<char, T, Error = Simple<char>>
) -> impl Parser<char, T, Error = Simple<char>> {
just(begin).ignore_then(parser).then_ignore(just(end))
} Calling it like |
I'm not really sure what to say. The code you gave wouldn't parse |
Ok sorry let me give you a full example (the code for use chumsky::prelude::*;
fn group<T>(
begin: &'static str,
end: &'static str,
parser: impl Parser<char, T, Error = Simple<char>>
) -> impl Parser<char, T, Error = Simple<char>> {
just(begin).ignore_then(parser).then_ignore(just(end))
}
#[derive(Debug, Eq, PartialEq)]
enum Token {
Tag(Tag),
Verbatim(char)
}
impl Token {
fn lexer() -> impl Parser<char, Self, Error = Simple<char>> {
let tag = group("{{", "}}", Tag::lexer()).map(Self::Tag);
let verbatim = any().map(Self::Verbatim);
choice((tag, verbatim))
}
}
#[derive(Debug, Eq, PartialEq)]
struct Tag;
impl Tag {
fn lexer() -> impl Parser<char, Self, Error = Simple<char>> {
just("foo").map(|_| Self)
}
}
fn lexer() -> impl Parser<char, Vec<Token>, Error = Simple<char>> {
Token::lexer().repeated().then_ignore(end())
}
#[test]
fn parse_tag_foo() {
let tokens = lexer().parse("{{foo}}").unwrap();
assert_eq!(&tokens, &[Token::Tag(Tag)]);
}
#[test]
#[should_panic]
fn parse_tag_bar() {
lexer().parse("{{bar}}").unwrap();
}
#[test]
#[should_panic]
fn parse_tag_foo_unclosed() {
lexer().parse("{{foo").unwrap();
} This parses everything that doesn't match all of the parsers of the first choice as the second choice, i.e. accepting all input:
What I want/need/.. (possibly there's another way to express this that I'm not aware of) is to enter the first choice if its first parser matches (the |
This parser accepts any character. It appears in a I guess what you really want is a way to do
Right now, |
Yes, I see why choice doesn't work for my case. A branch(just("{{"))
.then(Tag::lexer().then_ignore(just("}}")).map(Self::Tag))
.or_branch(...)
.or_else(any().map(Self::Verbatim)) I have no idea how hard this would be to implement or if that's at all feasible. |
The API you suggest would just do the same think as your current parser though. It's |
Also, just from a quick look |
I'm wondering whether I can generalise this a bit further, even, to |
Why not use |
Because having separate combinators for |
With |
I'm trying to parse a simple tag-like language, for example
foo{{x}}bar
would be a valid input. I tried usingchoice
to parse this, like so:However, this also parses
{{
as two verbatim characters, instead of as a tag delimiter. How can I make choice prefer the first parser?The text was updated successfully, but these errors were encountered: