aimx/literals/number.rs
1//! Numeric literal parsing for AIMX expressions.
2//!
3//! Provides parsers for numeric literals (integers, floats, scientific notation, and
4//! special values) used by the expression literal layer.
5
6use nom::{
7 IResult, Parser,
8 branch::alt,
9 bytes::complete::tag,
10 character::complete::{char, digit1, one_of},
11 combinator::{map, map_res, opt, recognize},
12};
13
14/// Parse a number literal into `f64`.
15///
16/// Accepts standard decimal, fractional, scientific (`e`/`E`), and special
17/// values (`NaN`, `±Inf`) used by AIMX.
18///
19/// Returns remaining input and parsed value.
20pub fn parse_number(input: &str) -> IResult<&str, f64> {
21 // First try to parse special float values
22 if let Ok(result) = alt((
23 map(tag::<_, _, nom::error::Error<&str>>("NaN"), |_| f64::NAN),
24 map(tag::<_, _, nom::error::Error<&str>>("Inf"), |_| f64::INFINITY),
25 map(tag::<_, _, nom::error::Error<&str>>("+Inf"), |_| f64::INFINITY),
26 map(tag::<_, _, nom::error::Error<&str>>("-Inf"), |_| {
27 f64::NEG_INFINITY
28 }),
29 ))
30 .parse(input)
31 {
32 return Ok(result);
33 }
34
35 // If special values don't match, try regular numbers
36 map_res(
37 alt((parse_scientific_notation, parse_float, parse_integer)),
38 |s: &str| s.parse::<f64>(),
39 )
40 .parse(input)
41}
42
43/// Parse an unsigned 32-bit integer.
44///
45/// Consumes one or more decimal digits and returns `u32` with remaining input.
46/// Used for indices and other non-negative values.
47pub fn parse_unsigned(input: &str) -> IResult<&str, u32> {
48 map_res(digit1, |s: &str| s.parse::<u32>()).parse(input)
49}
50
51/// Parse numbers in scientific notation for `parse_number`.
52///
53/// Internal helper; not intended for direct use.
54fn parse_scientific_notation(input: &str) -> IResult<&str, &str> {
55 recognize((
56 alt((parse_float, parse_integer)),
57 one_of("eE"),
58 opt(one_of("+-")),
59 digit1,
60 ))
61 .parse(input)
62}
63
64/// Parse floating-point numbers for `parse_number`.
65///
66/// Internal helper; accepts signed and unsigned decimal forms.
67
68fn parse_float(input: &str) -> IResult<&str, &str> {
69 recognize((
70 opt(char('-')),
71 alt((
72 // Pattern: digits.digits (e.g., 123.456)
73 recognize((digit1, char('.'), digit1)),
74 // Pattern: .digits (e.g., .5)
75 recognize((char('.'), digit1)),
76 // Pattern: digits. (e.g., 123.)
77 recognize((digit1, char('.'))),
78 )),
79 ))
80 .parse(input)
81}
82
83/// Parse integer numbers for `parse_number`.
84///
85/// Internal helper; accepts optional leading `-`.
86fn parse_integer(input: &str) -> IResult<&str, &str> {
87 recognize((opt(char('-')), digit1)).parse(input)
88}