Using the nom crate, I'm trying to write a parser that can recognize signed i32
number from a String
, i.e. can transform the string -42
into the i32
representation.
So far I've come up with the following, but I'm failing to parse negative numbers:
use nom::types::CompleteStr;
use std::str::FromStr;
named!(
i32_parser<CompleteStr, i32>,
map_res!(nom::digit, |CompleteStr(s)| i32::from_str(s))
);
#[test]
fn parse_i32_positive() {
assert_eq!(
i32_parser(CompleteStr::from("42")),
Ok((CompleteStr::from(""), 42))
);
}
#[test]
fn parse_i32_negative() {
assert_eq!(
i32_parser(CompleteStr::from("-42")),
Ok((CompleteStr::from(""), -42))
);
}
I've also tried the following, but with a cryptic compilation error:
named!(
i32_parser<CompleteStr, i32>,
map_res!(alt!(char!('-') | nom::digit), |CompleteStr(s)| i32::from_str(s))
);
^ expected char, found struct `nom::types::CompleteStr`
Any suggestion on how to fix it? Or a simpler way to achieve that with nom?
I'm explicitly looking to implement this with nom because I'm trying to parse a more complex structure. i32::from_str(s)
works for simple strings but it's not what I'm looking for.
The recognize!
macro can help you. It returns the parsed input string instead of the parser output, which can then be converted as usual. For example:
named!(i32_parser<&str, i32>,
map_res!(
recognize!(tuple!(opt!(char!('-')), digit)),
FromStr::from_str)
);
alt!(char!('-') | nom::digit)
"returns" a char, so your lambda needs to accept a char as argument. And it is possibly '-'
, so calling i32::from_str
on it will fail at runtime.
Instead of handle both the sign and digits in a single step, you should decompose your problem in two, eg. using do_parse
.
named!(
i32_parser<CompleteStr, i32>,
do_parse!(
minus: opt!(char!('-')) >>
digits: many1!(digit) >>
({
let sign = if minus.is_some() { -1 } else { 1 };
let mut number = 0;
for digit in digits {
number = number*10 + i32::from_str(digit.0).unwrap();
}
sign * number
})
)
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With