somen_language/
numeric.rs1use somen::prelude::*;
3
4use crate::character::{character, Character};
5
6pub mod float;
7pub mod integer;
8
9pub fn signed<'a, N, F, P, I, C>(mut parser: F, plus_sign: bool) -> impl Parser<I, Output = N> + 'a
14where
15 F: FnMut(bool) -> P + 'a,
16 P: Parser<I, Output = N> + 'a,
17 I: Input<Ok = C> + ?Sized + 'a,
18 C: Character + 'a,
19{
20 sign(plus_sign)
21 .opt()
22 .then(move |sign| parser(sign.unwrap_or_default()))
23 .expect("a signed number")
24}
25
26#[inline]
31pub fn unsigned<'a, N, F, P, I, C>(parser: F) -> impl Parser<I, Output = N> + 'a
32where
33 F: FnOnce(bool) -> P,
34 P: Parser<I, Output = N> + 'a,
35 I: Positioned<Ok = C> + ?Sized,
36 C: Character,
37{
38 parser(false)
39}
40
41pub fn digit<'a, I, C>(radix: u8) -> impl Parser<I, Output = C> + 'a
43where
44 I: Positioned<Ok = C> + ?Sized + 'a,
45 C: Character + 'a,
46{
47 let digit = is(move |c: &C| c.is_digit(radix));
48
49 #[cfg(feature = "alloc")]
50 {
51 digit.expect(alloc::format!("a digit with radix {radix}"))
52 }
53 #[cfg(not(feature = "alloc"))]
54 {
55 digit.expect("a digit")
56 }
57}
58
59pub fn non_zero_digit<'a, I, C>(radix: u8) -> impl Parser<I, Output = C> + 'a
61where
62 I: Positioned<Ok = C> + ?Sized + 'a,
63 C: Character + 'a,
64{
65 let digit = is(move |c: &C| c.is_digit(radix) && !c.eq_byte(b'0'));
66
67 #[cfg(feature = "alloc")]
68 {
69 digit.expect(alloc::format!("a non-zero digit with radix {radix}"))
70 }
71 #[cfg(not(feature = "alloc"))]
72 {
73 digit.expect("a non-zero digit")
74 }
75}
76
77#[inline]
79pub fn digits<'a, I, C>(radix: u8) -> impl IterableParser<I, Item = C> + 'a
80where
81 I: Input<Ok = C> + ?Sized + 'a,
82 C: Character + 'a,
83{
84 (non_zero_digit(radix).once(), digit(radix).repeat(..)).or(character(b'0').once())
85}
86
87#[inline]
89pub fn digits_trailing_zeros<'a, I, C>(radix: u8) -> impl IterableParser<I, Item = C> + 'a
90where
91 I: Input<Ok = C> + ?Sized + 'a,
92 C: Character + 'a,
93{
94 digit(radix).repeat(1..)
95}
96
97#[inline]
99pub fn digits_fixed<'a, I, C>(length: usize, radix: u8) -> impl IterableParser<I, Item = C> + 'a
100where
101 I: Positioned<Ok = C> + ?Sized + 'a,
102 C: Character + 'a,
103{
104 digit(radix).times(length)
105}
106
107pub fn sign<'a, I, C>(plus_sign: bool) -> impl Parser<I, Output = bool> + 'a
111where
112 I: Input<Ok = C> + ?Sized + 'a,
113 C: Character + 'a,
114{
115 let minus = character(b'-').map(|_| true);
116 if plus_sign {
117 minus.or(character(b'+').map(|_| false)).left()
118 } else {
119 minus.right()
120 }
121}