I am writing a small parser in Rust using nom
and I wanted to implement a simple function that given a delimiting &str would return a delimited parser using my delimiting &str.
After fighting the compiler for half an hour, I ended up with this monstrosity that does not even compile:
use nom::{
branch::alt,
bytes::complete::{escaped, tag},
character::complete::{multispace0, one_of, satisfy, space0},
combinator::{map, not, recognize},
error::ParseError,
sequence::{delimited, pair, tuple},
AsChar, Compare, FindToken, IResult, InputIter, InputTake, InputTakeAtPosition, Parser,
};
pub fn string_literal(input: &str) -> IResult<&str, &str> {
fn parse_delimited_string<
'a,
I: Clone
+ InputTake
+ Compare<&'a str>
+ nom::Slice<std::ops::RangeFrom<usize>>
+ nom::InputIter
+ nom::Offset
+ nom::InputLength
+ nom::UnspecializedInput
+ 'a,
O,
E: ParseError<I> + 'a,
>(
delimited_by: &'a str,
) -> impl Parser<I, I, E> + 'a
where
<I as InputIter>::Item: std::marker::Copy,
<I as InputIter>::Item: AsChar,
for<'b> &'a str: FindToken<<I as InputIter>::Item>,
{
delimited(
tag(delimited_by),
escaped(
not(tag("\\")),
delimited_by.as_bytes()[0] as char,
one_of(delimited_by),
),
tag(delimited_by),
)
}
alt((parse_delimited_string("\'"), parse_delimited_string("\"")))(input)
}
This gives me a compiler error:
error[E0277]: the trait bound `&str: UnspecializedInput` is not satisfied
--> src/expression.rs:102:10
|
102 | alt((parse_delimited_string("\'"), parse_delimited_string("\"")))(input)
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `UnspecializedInput` is not implemented for `&str`
|
note: required by a bound in `parse_delimited_string`
--> src/expression.rs:79:15
|
70 | fn parse_delimited_string<
| ---------------------- required by a bound in this function
...
79 | + nom::UnspecializedInput
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `parse_delimited_string`
It's clear that I want to parse strings that are delimited by either '
or "
- my use case is pretty simple, so at this point I will just write the two parsers by hand and not use a generating function because just look at this thing.
Is there any way I can write this concisely without exploding in the size of the template? It seems like such a simple task, but it proved to be surprisingly difficult.
I think you can copy the example from here, which I've pasted below. You may have to adapt it slightly to handle both single and double quotes.