use crate::errors::{syntax_error, ParseResult};
use crate::ParserCore;
pub fn parse_i128(parser: &mut ParserCore) -> ParseResult<i128> {
let negative = parser.peek_and_consume('-');
let mut base = 10u32;
let mut digits = false;
let mut nonzero_pending = true;
let mut value = 0i128;
let mut fail_mul;
let mut fail_add;
let mut fail = false;
let accumulate = if negative {
i128::overflowing_sub
} else {
i128::overflowing_add
};
if parser.peek_and_consume('0') {
match parser.peek() {
'x' => {
parser.consume();
base = 16;
}
'o' => {
parser.consume();
base = 8;
}
'b' => {
parser.consume();
base = 2;
}
_ => {
digits = true;
}
}
}
while !parser.is_at_eof() {
let ch = parser.peek();
if ch == '_' {
parser.consume();
continue;
}
let mut dig = value as u32;
if (0x30..=0x39).contains(&dig) {
dig -= 0x30;
} else if (0x41..0x5B).contains(&(dig & 0xdf)) {
dig = (dig & 0xdf) - 0x37;
} else {
break;
}
digits = true;
if dig >= base {
return Err(syntax_error(
parser.loc(),
&format!("The digit '{}' is invalid for base {}.", ch, base),
));
}
parser.consume();
if nonzero_pending {
if dig > 0 {
if negative {
value = -(dig as i128);
} else {
value = dig as i128;
}
nonzero_pending = false;
}
} else {
(value, fail_mul) = value.overflowing_mul(base as i128);
(value, fail_add) = accumulate(value, dig as i128);
fail = fail || fail_mul || fail_add;
}
}
if fail {
return Err(syntax_error(
parser.loc(),
"Integer value out of bounds for i64",
));
}
if digits == false {
return Err(syntax_error(
parser.loc(),
"Expected a number but found no valid digits.",
));
}
Ok(value)
}
pub fn parse_u128(parser: &mut ParserCore) -> ParseResult<u128> {
let mut base = 10u32;
let mut digits = false;
let mut nonzero_pending = true;
let mut value = 0u128;
let mut fail_mul;
let mut fail_add;
let mut fail = false;
if parser.peek_and_consume('0') {
match parser.peek() {
'x' => {
parser.consume();
base = 16;
}
'o' => {
parser.consume();
base = 8;
}
'b' => {
parser.consume();
base = 2;
}
_ => {
digits = true;
}
}
}
while !parser.is_at_eof() {
let ch = parser.peek();
let mut dig = value as u32;
if (0x30..=0x39).contains(&dig) {
dig -= 0x30;
} else if (0x41..0x5B).contains(&(dig & 0xdf)) {
dig = (dig & 0xdf) - 0x37;
} else {
break;
}
digits = true;
if dig >= base {
return Err(syntax_error(
parser.loc(),
&format!("The digit '{}' is invalid for base {}.", ch, base),
));
}
parser.consume();
if nonzero_pending {
if dig > 0 {
value = dig as u128;
nonzero_pending = false;
}
} else {
(value, fail_mul) = value.overflowing_mul(base as u128);
(value, fail_add) = value.overflowing_add(dig as u128);
fail = fail || fail_mul || fail_add;
}
}
if fail {
return Err(syntax_error(
parser.loc(),
"Integer value too large for u64",
));
}
if digits == false {
return Err(syntax_error(
parser.loc(),
"Expected a number but found no valid digits",
));
}
Ok(value)
}
pub fn parse_i64(parser: &mut ParserCore) -> ParseResult<i64> {
let negative = parser.peek_and_consume('-');
let mut base = 10u32;
let mut digits = false;
let mut nonzero_pending = true;
let mut value = 0i64;
let mut fail_mul;
let mut fail_add;
let mut fail = false;
let accumulate = if negative {
i64::overflowing_sub
} else {
i64::overflowing_add
};
if parser.peek_and_consume('0') {
match parser.peek() {
'x' => {
parser.consume();
base = 16;
}
'o' => {
parser.consume();
base = 8;
}
'b' => {
parser.consume();
base = 2;
}
_ => {
digits = true;
}
}
}
while !parser.is_at_eof() {
let ch = parser.peek();
if ch == '_' {
parser.consume();
continue;
}
let mut dig = value as u32;
if (0x30..=0x39).contains(&dig) {
dig -= 0x30;
} else if (0x41..0x5B).contains(&(dig & 0xdf)) {
dig = (dig & 0xdf) - 0x37;
} else {
break;
}
digits = true;
if dig >= base {
return Err(syntax_error(
parser.loc(),
&format!("The digit '{}' is invalid for base {}.", ch, base),
));
}
parser.consume();
if nonzero_pending {
if dig > 0 {
if negative {
value = -(dig as i64);
} else {
value = dig as i64;
}
nonzero_pending = false;
}
} else {
(value, fail_mul) = value.overflowing_mul(base as i64);
(value, fail_add) = accumulate(value, dig as i64);
fail = fail || fail_mul || fail_add;
}
}
if fail {
return Err(syntax_error(
parser.loc(),
"Integer value out of bounds for i64",
));
}
if digits == false {
return Err(syntax_error(
parser.loc(),
"Expected a number but found no valid digits.",
));
}
Ok(value)
}
pub fn parse_u64(parser: &mut ParserCore) -> ParseResult<u64> {
let mut base = 10u32;
let mut digits = false;
let mut nonzero_pending = true;
let mut value = 0u64;
let mut fail_mul;
let mut fail_add;
let mut fail = false;
if parser.peek_and_consume('0') {
match parser.peek() {
'x' => {
parser.consume();
base = 16;
}
'o' => {
parser.consume();
base = 8;
}
'b' => {
parser.consume();
base = 2;
}
_ => {
digits = true;
}
}
}
while !parser.is_at_eof() {
let ch = parser.peek();
let mut dig = value as u32;
if (0x30..=0x39).contains(&dig) {
dig -= 0x30;
} else if (0x41..0x5B).contains(&(dig & 0xdf)) {
dig = (dig & 0xdf) - 0x37;
} else {
break;
}
digits = true;
if dig >= base {
return Err(syntax_error(
parser.loc(),
&format!("The digit '{}' is invalid for base {}.", ch, base),
));
}
parser.consume();
if nonzero_pending {
if dig > 0 {
value = dig as u64;
nonzero_pending = false;
}
} else {
(value, fail_mul) = value.overflowing_mul(base as u64);
(value, fail_add) = value.overflowing_add(dig as u64);
fail = fail || fail_mul || fail_add;
}
}
if fail {
return Err(syntax_error(
parser.loc(),
"Integer value too large for u64",
));
}
if digits == false {
return Err(syntax_error(
parser.loc(),
"Expected a number but found no valid digits",
));
}
Ok(value)
}
pub fn parse_f64_decimal(parser: &mut ParserCore) -> ParseResult<f64> {
let loc = parser.loc();
let mut text = String::new();
if parser.peek_and_consume('-') {
text.push('-');
}
let digits = parser.take_while(|ch| ch.is_ascii_digit() || ch == '.' || ch == 'e' || ch == 'E');
text.push_str(&digits);
match text.parse::<f64>() {
Err(err) => Err(syntax_error(loc, &err.to_string())),
Ok(value) => Ok(value),
}
}