I'm currently trying to parse a small domain-specific language and am looking into parser combinator crates. It seems like nom
is a popular one but I'm struggling to understand how I can use it for my use case.
As I understand it, one makes many small parser functions for basic parsing and then composes these to form a higher logic (sorry if I'm nor using the proper syntax for these terms).
So currently I have a subproblem like this:
I want to parse strings like this: "1,2,3,4-7,9:22"
which can contain an arbitrary number of comma-separated values. The values delimited by a hyphen or colon represent ranges.
So far I wrote this:
fn range_sep(input: &str) -> IResult<&str, &str> {
recognize(alt((char('-'), char(':'))))(input)
}
fn range(input: &str) -> IResult<&str, &str> {
let test = tuple((digit1, range_sep, digit1))(input)?;
let string = test.1.0.to_owned() + test.1.1 + test.1.2;
Ok(&string)
}
fn id_with_opt_range(input: &str) -> IResult<&str, &str> {
alt((digit1, range))(input)
}
fn num_list(input: &str) -> IResult<&str, Vec<&str>> {
separated_list1(char(','), id_with_opt_range)(input)
}
This is probably overly verbose but I'm just starting out. As can be seen, first the separators for the potential ranges are parsed, then the ranges, then the full list which can contain eithers digits or a range.
However, the range
function doesn't compile because I can't return a &str
from it since it is a borrow created in the same function. On the other hand, I can't return the tuple because id_with_opt_range
expects a &str
as input.
Since each small parser hands its results to the next one, they all need to take &str
as input as far as I can see but maybe I misunderstood the concept here.
I would be grateful for any pointers as to what I can do here. Also, if anyone can suggest an accessible tutorial or some such for this crate (or another, possibly more suited one) I'd be grateful as well, I find it difficult to wrap my head around this.