dftp 0.1.0

dft instructions parser
Documentation
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete::{char, one_of};
use nom::character::is_alphanumeric;
use nom::combinator::{map, opt, recognize};
use nom::error::ErrorKind;
use nom::multi::{many0, many1};
use nom::sequence::{pair, preceded, terminated, tuple};
use nom::{AsChar, InputTakeAtPosition};

use crate::types::{Boolean, Float, Integer, Text, VResult};

pub fn text(input: &str) -> VResult<&str, Text> {
    map(textchars1, |result: &str| Text::from(result))(input)
}

pub fn boolean(input: &str) -> VResult<&str, Boolean> {
    map(alt((tag("true"), tag("false"))), |result: &str| {
        result.parse().unwrap()
    })(input)
}

pub fn float(input: &str) -> VResult<&str, Float> {
    map(
        pair(
            opt(one_of("+-")),
            alt((
                recognize(tuple((
                    char('.'),
                    decimal,
                    opt(tuple((one_of("eE"), opt(one_of("+-")), decimal))),
                ))),
                recognize(tuple((
                    decimal,
                    opt(preceded(char('.'), decimal)),
                    one_of("eE"),
                    opt(one_of("+-")),
                    decimal,
                ))),
                recognize(tuple((decimal, char('.'), opt(decimal)))),
            )),
        ),
        |(sign, number): (Option<char>, &str)| match sign {
            Some(s) => format!("{s}{number}").as_str().parse().unwrap(),
            None => number.parse().unwrap(),
        },
    )(input)
}

pub fn integer(input: &str) -> VResult<&str, Integer> {
    map(decimal, |number: &str| {
        number.replace("_", "").parse().unwrap()
    })(input)
}

pub fn textchars1<T>(input: T) -> VResult<T, T>
where
    T: InputTakeAtPosition,
    <T as InputTakeAtPosition>::Item: AsChar,
{
    input.split_at_position1_complete(
        |item| is_textchar(item.as_char() as u8),
        ErrorKind::AlphaNumeric,
    )
}

fn is_textchar(input: u8) -> bool {
    !(is_alphanumeric(input) || input == b'.')
}

fn decimal(input: &str) -> VResult<&str, &str> {
    recognize(many1(terminated(one_of("0123456789"), many0(char('_')))))(input)
}