use combine::*;
use combine::char::{char, digit};
use combine::range::{range, recognize};
use combine::primitives::RangeStream;
parse!(boolean() -> bool, {
choice((
(char('t'), range("rue"),),
(char('f'), range("alse"),),
)).map(|p| p.0 == 't')
});
parse!(parse_integer() -> &'a str, {
recognize((
optional(choice([char('-'), char('+')])),
choice((
char('0'),
(
satisfy(|c| '1' <= c && c <= '9'),
skip_many((
optional(char('_')),
skip_many1(digit()),
)),
).map(|t| t.0),
)),
))
});
parse!(integer() -> i64, {
parse_integer()
.and_then(|s| s.replace("_", "").parse())
.message("While parsing an Integer")
});
parse!(frac() -> &'a str, {
recognize((
char('.'),
skip_many1(digit()),
skip_many((
optional(char('_')),
skip_many1(digit()),
)),
))
});
parse!(exp() -> &'a str, {
recognize((
one_of("eE".chars()),
parse_integer(),
))
});
parse!(parse_float() -> &'a str, {
recognize((
try((parse_integer(), look_ahead(one_of("eE.".chars())))),
choice((
exp(),
(
frac(),
optional(exp()),
).map(|_| "")
)),
))
});
parse!(float() -> f64, {
parse_float()
.and_then(|s| s.replace("_", "").parse())
.message("While parsing a Float")
});