I'm trying to write a nom parser that recognizes multiline comments...
/*
yo!
*/
...and consumes/discards (same thing, right?) the result:
use nom::{
bytes::complete::{tag, take_until},
error::{ErrorKind, ParseError},
sequence::preceded,
IResult,
};
fn multiline_comment<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
preceded(tag("/*"), take_until("*/"))(i)
}
This almost works. I know the take_until stops just before the */
, but I don't know what to do to make it include it.
#[test]
fn should_consume_multiline_comments() {
assert_eq!(
multiline_comment::<(&str, ErrorKind)>("/*abc\n\ndef*/"),
Ok(("", "/*abc\n\ndef*/"))
);
}
gives the result
thread 'should_consume_multiline_comments' panicked at 'assertion failed: `(left == right)`
left: `Ok(("*/", "abc\n\ndef"))`,
right: `Ok(("", "/*abc\n\ndef*/"))`'
So my question is, how do I get the full comment, including the ending */
Thanks!
I am assuming that you don't really want the returned string to have both preceding /*
and closing */
intact - since preceded
always discards the match from the first parser, you are never going to get that using preceded
. I assume your main concern is ensuring that the closing */
is actually consumed.
For this you can use delimited
rather than preceded
:
fn multiline_comment<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
delimited(tag("/*"), is_not("*/"), tag("*/"))(i)
}
This passes this test:
assert_eq!(
multiline_comment1::<(&str, ErrorKind)>("/*abc\n\ndef*/"),
Ok(("", "abc\n\ndef"))
);
so you can be sure that the closing */
has been consumed.