dftp/combinators/
types.rs1use 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}