-
I've tried to write a simple parser using the library to get a feel for it. The parser can parse expressions such as "1 = 1" or "2=2" but not "1=3". Also, the expression can be and'ed or or'ed together, and grouped. The (whole) code is as follows: use chumsky::{prelude::*, text::digits};
pub type Span = std::ops::Range<usize>;
pub type Spanned<T> = (T, Span);
fn parser() -> impl Parser<char, Spanned<String>, Error = Simple<char>> {
let single_clause = digits(10)
.then(just('=').padded())
.then(digits(10))
.try_map(|((lhs, _), rhs), span| match lhs == rhs {
true => Ok(format!("{lhs} == {rhs}")),
false => Err(Simple::custom(span, format!("{lhs} != {rhs}"))),
});
recursive(|nested| {
let inner_expr = single_clause.or(nested.delimited_by(just('('), just(')')));
let and_case = inner_expr
.clone()
.separated_by(just("or").padded())
.map(|v| v.join(" OR "));
let or_case = inner_expr
.clone()
.separated_by(just("and").padded())
.map(|v| v.join(" AND "));
inner_expr.or(or_case).or(and_case)
})
.map_with_span(|tok, span| (tok, span))
.then_ignore(end())
}
fn main() {
dbg!(parser().parse("1 = 1 or 2 = 2"));
} The output is:
If I understand the issue correctly, the parser terminates parsing after What am I missing? Thanks |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
You are close, but are missing a key point of A simplified example of this problem is: let result = just("fun").or(just("function")).then_ignore(end()).parse("function");
assert!(result.is_err()); This will error because assert!(parser.parse("1 = 1 or 2 = 2").is_ok());
assert!(parser.parse("1 = 1 and 2 = 2").is_ok()); This is because whichever parser you chose to have parse the input first, will successfully parse the start, but then not be able to parse either What I assume you're after, is being able to chain // This replaces lines 18-28 or your parser
inner_expr
.clone()
.then(
choice((
just("or")
.padded()
.ignore_then(nested.clone())
.map(|n| format!("OR {n}")),
just("and")
.padded()
.ignore_then(nested.clone())
.map(|n| format!("AND {n}")),
))
.repeated()
.collect::<String>(),
)
.map(|(lhs, rhs)| format!("{lhs}{rhs}")) This does a couple things different. At first it will accept any |
Beta Was this translation helpful? Give feedback.
You are close, but are missing a key point of
or
parsers. In anor
chain, the first parser that is able to successfully parse some of the input will "win" the chain, and stop the chain from parsing further. This means that because yourinner_expr
is written first, it will successfully parse the"1 = 1"
and what remains of the input is" or 2 = 2"
. Parsing fails here, because there is no repeat, and even if there was, nothing could parse the remaining input successfully.A simplified example of this problem is:
This will error because
just("fun")
will successfully eat the first thr…