use combine::char::{char, digit, hex_digit, oct_digit, string};
use combine::range::{range, recognize};
use combine::stream::RangeStream;
use combine::*;
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, {
choice!(
attempt(parse_hex_integer()),
attempt(parse_octal_integer()),
attempt(parse_binary_integer()),
parse_integer()
.and_then(|s| s.replace("_", "").parse())
.message("While parsing an Integer")
)
});
parse!(parse_hex_integer() -> i64, {
string("0x").with(
recognize((
hex_digit(),
skip_many((
optional(char('_')),
skip_many1(hex_digit()),
)),
).map(|t| t.0)
)).and_then(|s: &str| i64::from_str_radix(&s.replace("_", ""), 16))
.message("While parsing a hexadecimal Integer")
});
parse!(parse_octal_integer() -> i64, {
string("0o").with(
recognize((
oct_digit(),
skip_many((
optional(char('_')),
skip_many1(oct_digit()),
)),
).map(|t| t.0)
)).and_then(|s: &str| i64::from_str_radix(&s.replace("_", ""), 8))
.message("While parsing an octal Integer")
});
parse!(parse_binary_integer() -> i64, {
string("0b").with(
recognize((
satisfy(|c: char| c.is_digit(0x2)),
skip_many((
optional(char('_')),
skip_many1(satisfy(|c: char| c.is_digit(0x2))),
)),
).map(|t| t.0)
)).and_then(|s: &str| i64::from_str_radix(&s.replace("_", ""), 2))
.message("While parsing a binary 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((
attempt((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")
});