use crate::parser::ast::AstGeneratorContext;
use crate::parser::lexer::token::TokenTy;
use crate::parser::{ast::AstNode, fragment::Fragment};
use num::bigint::ParseBigIntError;
use num::{BigUint, Num};
#[derive(Debug)]
pub struct IntegerLiteral<'src> {
pub fragment: Fragment<'src>,
pub value: BigUint,
}
#[derive(Clone, Debug)]
pub enum IntegerLiteralParsingError<'src> {
ExpectedIntegerLiteral {
at: Fragment<'src>,
},
NumParsingError {
error: ParseBigIntError,
at: Fragment<'src>,
},
}
impl<'src> AstNode<'src> for IntegerLiteral<'src> {
type Error = IntegerLiteralParsingError<'src>;
fn fragment(&self) -> Fragment<'src> {
self.fragment
}
fn try_parse(ctx: &mut AstGeneratorContext<'src>) -> Result<Self, Self::Error>
where
Self: Sized,
{
let fragment: Fragment = ctx
.next_if_is(TokenTy::IntegerLiteral)
.ok_or(IntegerLiteralParsingError::ExpectedIntegerLiteral {
at: ctx.peek_fragment(),
})?
.fragment;
let literal: &str = fragment.inner;
let prefixes = [("0x", 16), ("0X", 16), ("0o", 8), ("0b", 2), ("0B", 2)];
for (prefix, radix) in prefixes {
if let Some(prefix_stripped) = literal.strip_prefix(prefix) {
let fully_stripped: &str = prefix_stripped.trim_start_matches('_');
let value: BigUint = BigUint::from_str_radix(fully_stripped, radix).map_err(
|err: ParseBigIntError| IntegerLiteralParsingError::NumParsingError {
error: err,
at: fragment,
},
)?;
return Ok(IntegerLiteral { fragment, value });
}
}
let value: BigUint = BigUint::from_str_radix(literal, 10).map_err(|err| {
IntegerLiteralParsingError::NumParsingError {
error: err,
at: fragment,
}
})?;
Ok(IntegerLiteral { fragment, value })
}
}