dftp/combinators/
types.rs

1use nom::branch::alt;
2use nom::bytes::complete::tag;
3use nom::character::complete::{char, one_of};
4use nom::character::is_alphanumeric;
5use nom::combinator::{map, opt, recognize};
6use nom::error::ErrorKind;
7use nom::multi::{many0, many1};
8use nom::sequence::{pair, preceded, terminated, tuple};
9use nom::{AsChar, InputTakeAtPosition};
10
11use crate::types::{Boolean, Float, Integer, Text, VResult};
12
13pub fn text(input: &str) -> VResult<&str, Text> {
14    map(textchars1, |result: &str| Text::from(result))(input)
15}
16
17pub fn boolean(input: &str) -> VResult<&str, Boolean> {
18    map(alt((tag("true"), tag("false"))), |result: &str| {
19        result.parse().unwrap()
20    })(input)
21}
22
23pub fn float(input: &str) -> VResult<&str, Float> {
24    map(
25        pair(
26            opt(one_of("+-")),
27            alt((
28                recognize(tuple((
29                    char('.'),
30                    decimal,
31                    opt(tuple((one_of("eE"), opt(one_of("+-")), decimal))),
32                ))),
33                recognize(tuple((
34                    decimal,
35                    opt(preceded(char('.'), decimal)),
36                    one_of("eE"),
37                    opt(one_of("+-")),
38                    decimal,
39                ))),
40                recognize(tuple((decimal, char('.'), opt(decimal)))),
41            )),
42        ),
43        |(sign, number): (Option<char>, &str)| match sign {
44            Some(s) => format!("{s}{number}").as_str().parse().unwrap(),
45            None => number.parse().unwrap(),
46        },
47    )(input)
48}
49
50pub fn integer(input: &str) -> VResult<&str, Integer> {
51    map(decimal, |number: &str| {
52        number.replace("_", "").parse().unwrap()
53    })(input)
54}
55
56pub fn textchars1<T>(input: T) -> VResult<T, T>
57where
58    T: InputTakeAtPosition,
59    <T as InputTakeAtPosition>::Item: AsChar,
60{
61    input.split_at_position1_complete(
62        |item| is_textchar(item.as_char() as u8),
63        ErrorKind::AlphaNumeric,
64    )
65}
66
67fn is_textchar(input: u8) -> bool {
68    !(is_alphanumeric(input) || input == b'.')
69}
70
71fn decimal(input: &str) -> VResult<&str, &str> {
72    recognize(many1(terminated(one_of("0123456789"), many0(char('_')))))(input)
73}