rust-nix/src/parser/token/number.rs

49 lines
1.4 KiB
Rust

use nom::Parser;
use super::{
SpanRef,
PResult,
Token,
Number,
IResultExt,
SpannedData,
SpanExt,
};
// should come after path
fn parse_number_span(span: SpanRef) -> PResult<()> {
// if not a path, everything that starts with an optional '-', optional '.'
// followed by digits is a number.
let (span, _) = nom::sequence::tuple((
nom::combinator::opt(nom::bytes::complete::tag("-")),
nom::combinator::opt(nom::bytes::complete::tag(".")),
nom::character::complete::digit1,
))(span)?;
// if we fail now, fail hard (upstream nix parses something crazy here).
// take up all alpha characters too, should be separated by something.
let (span, _) = nom::multi::many0_count(nom::branch::alt((
nom::character::complete::alphanumeric1.map(|_| ()),
nom::bytes::complete::tag(".").map(|_| ()),
nom::bytes::complete::tag("e").map(|_| ()),
)))(span).unrecoverable()?;
Ok((span, ()))
}
impl Number {
// should come after path
pub(super) fn parse(span: SpanRef) -> PResult<SpannedData<Token>> {
let (rem_span, num_span) = nom::combinator::recognize(parse_number_span)(span)?;
let num_s = num_span.as_str();
let num = if let Ok(num) = num_s.parse() {
Number::Integer(num)
} else if let Ok(num) = num_s.parse() {
Number::Float(num)
} else {
return nom::combinator::fail(span).unrecoverable();
};
Ok((rem_span, num_span.data(Token::Number(num))))
}
}