use crate::parser::trivia::from_utf8_unchecked;
use combine::parser::byte::{byte, bytes, digit, hex_digit, oct_digit};
use combine::parser::range::{range, recognize};
use combine::stream::RangeStream;
use combine::*;
parse!(boolean() -> bool, {
choice((
(byte(b't'), range(&b"rue"[..]),),
(byte(b'f'), range(&b"alse"[..]),),
)).map(|p| p.0 == b't')
});
parse!(integer() -> i64, {
choice!(
attempt(hex_int()),
attempt(oct_int()),
attempt(bin_int()),
dec_int()
.and_then(|s| s.replace("_", "").parse())
.message("While parsing an Integer")
)
});
parse!(dec_int() -> &'a str, {
recognize((
optional(choice([byte(b'-'), byte(b'+')])),
choice((
byte(b'0'),
(
satisfy(|c| (b'1'..=b'9').contains(&c)),
skip_many((
optional(byte(b'_')),
skip_many1(digit()),
)),
).map(|t| t.0),
)),
)).map(|b: &[u8]| {
unsafe { from_utf8_unchecked(b, "`digit` and `_` filter out npn-ASCII") }
})
});
parse!(hex_int() -> i64, {
bytes(b"0x").with(
recognize((
hex_digit(),
skip_many((
optional(byte(b'_')),
skip_many1(hex_digit()),
)),
).map(|t| t.0)
)).and_then(|b: &[u8]| {
let s = unsafe { from_utf8_unchecked(b, "`hex_digit` and `_` filter out npn-ASCII") };
i64::from_str_radix(&s.replace("_", ""), 16)
}).message("While parsing a hexadecimal Integer")
});
parse!(oct_int() -> i64, {
bytes(b"0o").with(
recognize((
oct_digit(),
skip_many((
optional(byte(b'_')),
skip_many1(oct_digit()),
)),
).map(|t| t.0)
)).and_then(|b: &[u8]| {
let s = unsafe { from_utf8_unchecked(b, "`oct_digit` and `_` filter out npn-ASCII") };
i64::from_str_radix(&s.replace("_", ""), 8)
}).message("While parsing a octal Integer")
});
parse!(bin_int() -> i64, {
bytes(b"0b").with(
recognize((
satisfy(|c: u8| c == b'0' || c == b'1'),
skip_many((
optional(byte(b'_')),
skip_many1(satisfy(|c: u8| c == b'0' || c == b'1')),
)),
).map(|t| t.0)
)).and_then(|b: &[u8]| {
let s = unsafe { from_utf8_unchecked(b, "`is_digit` and `_` filter out npn-ASCII") };
i64::from_str_radix(&s.replace("_", ""), 2)
}).message("While parsing a binary Integer")
});
parse!(float() -> f64, {
choice((
parse_float()
.and_then(|s| s.replace("_", "").parse()),
special_float(),
)).message("While parsing a Float")
});
parse!(parse_float() -> &'a str, {
recognize((
attempt((dec_int(), look_ahead(one_of([b'e', b'E', b'.'])))),
choice((
exp(),
(
frac(),
optional(exp()),
).map(|_| "")
)),
)).map(|b: &[u8]| {
unsafe { from_utf8_unchecked(b, "`dec_int`, `one_of`, `exp`, and `frac` filter out npn-ASCII") }
})
});
parse!(frac() -> &'a str, {
recognize((
byte(b'.'),
parse_zero_prefixable_int(),
)).map(|b: &[u8]| {
unsafe { from_utf8_unchecked(b, "`.` and `parse_zero_prefixable_int` filter out npn-ASCII") }
})
});
parse!(parse_zero_prefixable_int() -> &'a str, {
recognize((
skip_many1(digit()),
skip_many((
optional(byte(b'_')),
skip_many1(digit()),
)),
)).map(|b: &[u8]| {
unsafe { from_utf8_unchecked(b, "`digit` and `_` filter out npn-ASCII") }
})
});
parse!(exp() -> &'a str, {
recognize((
one_of([b'e', b'E']),
optional(one_of([b'+', b'-'])),
parse_zero_prefixable_int(),
)).map(|b: &[u8]| {
unsafe { from_utf8_unchecked(b, "`one_of` and `parse_zero_prefixable_int` filter out npn-ASCII") }
})
});
parse!(special_float() -> f64, {
attempt(optional(one_of([b'+', b'-'])).and(choice((inf(), nan()))).map(|(s, f)| {
match s {
Some(b'+') | None => f,
Some(b'-') => -f,
_ => unreachable!("one_of should prevent this"),
}
}))
});
parse!(inf() -> f64, {
range(&b"inf"[..]).map(|_| f64::INFINITY)
});
parse!(nan() -> f64, {
range(&b"nan"[..]).map(|_| f64::NAN)
});