udled_tokenizers/
numeric.rs

1use alloc::string::ToString;
2use udled::{
3    tokenizers::{opt, Digit, Peek},
4    AsChar, AsSlice, AsStr, Buffer, Error, Item, Reader, Span, Tokenizer, TokenizerExt,
5};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8pub struct Integer;
9
10impl<'input, B> Tokenizer<'input, B> for Integer
11where
12    B: Buffer<'input>,
13    B::Item: AsChar,
14{
15    type Token = Item<i128>;
16
17    fn to_token<'a>(&self, reader: &mut Reader<'_, 'input, B>) -> Result<Self::Token, Error> {
18        let start = reader.position();
19        let mut val: i128 = 0;
20        let base = 10;
21
22        let sign = if reader.eat('-').is_ok() { -1 } else { 1 };
23
24        loop {
25            let ch = reader.parse(Digit(base))?;
26
27            val = (base as i128) * val + (ch.value as i128);
28
29            if !reader.is(Digit(base)) {
30                break;
31            }
32        }
33
34        return Ok(Item::new(Span::new(start, reader.position()), val * sign));
35    }
36
37    fn peek(&self, reader: &mut Reader<'_, 'input, B>) -> bool {
38        reader.is(Peek((opt('-'), Digit(10))))
39    }
40}
41
42#[derive(Debug, Clone, Copy, Default)]
43pub struct Float;
44
45impl<'input, B> Tokenizer<'input, B> for Float
46where
47    B: Buffer<'input>,
48    B::Item: AsChar,
49    B::Source: AsSlice<'input>,
50    <B::Source as AsSlice<'input>>::Slice: AsStr<'input>,
51{
52    type Token = Item<f64>;
53
54    fn to_token<'a>(&self, reader: &mut Reader<'_, 'input, B>) -> Result<Self::Token, Error> {
55        let slice = reader.parse(
56            (
57                Integer,
58                '.',
59                Digit(10).many(),
60                ('e'.or('E'), opt('-'), Digit(10).many()).optional(),
61            )
62                .slice(),
63        )?;
64
65        let float: f64 = slice
66            .value
67            .as_str()
68            .parse()
69            .map_err(|err: core::num::ParseFloatError| reader.error(err.to_string()))?;
70
71        Ok(Item::new(slice.span, float))
72    }
73
74    fn peek(&self, reader: &mut Reader<'_, 'input, B>) -> bool {
75        reader.is(Peek((Integer, '.')))
76    }
77}
78
79#[cfg(test)]
80mod test {
81    use udled::Input;
82
83    use super::{Float, Integer};
84
85    #[test]
86    fn integer() {
87        let mut input = Input::new("10203 0 42");
88
89        let (a, _, b, _, c) = input.parse((Integer, ' ', Integer, ' ', Integer)).unwrap();
90
91        assert_eq!(a.value, 10203);
92        assert_eq!(b.value, 0);
93        assert_eq!(c.value, 42);
94    }
95
96    // #[test]
97    // fn int() {
98    //     let mut input = Input::new("0x202 0b11 42");
99
100    //     let (a, _, b, _, c) = input.parse((Int, Ws, Int, Ws, Int)).unwrap();
101
102    //     assert_eq!(a.value, 0x202);
103    //     assert_eq!(b.value, 0b11);
104    //     assert_eq!(c.value, 42);
105    // }
106
107    #[test]
108    fn float() {
109        let mut input = Input::new("1.0000033 2003.303 12.03e-20");
110
111        let (a, _, b, _, c) = input.parse((Float, ' ', Float, ' ', Float)).unwrap();
112
113        assert_eq!(a.value, 1.0000033);
114        assert_eq!(b.value, 2003.303);
115        assert_eq!(c.value, 12.03e-20);
116    }
117}