use nom::branch::alt;
use nom::bytes::complete::{tag, take_until};
use nom::character::complete::{alpha1, alphanumeric1, char, digit1, multispace0, one_of};
use nom::combinator::{map, map_res, opt, recognize, value};
use nom::multi::{many0, many1, separated_list1};
use crate::TfRes;
use nom::sequence::{delimited, pair, preceded, terminated, tuple};
use std::str;
use std::str::FromStr;
pub fn ws<'a, F: 'a, O>(inner: F) -> impl FnMut(&'a str) -> TfRes<&'a str, O>
where
F: FnMut(&'a str) -> TfRes<&'a str, O>,
{
delimited(multispace0, inner, multispace0)
}
pub fn tstring(input: &str) -> TfRes<&str, &str> {
ws(recognize(pair(
alt((alpha1, tag("_"))),
many0(alt((alphanumeric1, tag("_")))),
)))(input)
}
pub fn qstring(input: &str) -> TfRes<&str, &str> {
ws(recognize(delimited(tag("\""), tstring, tag("\""))))(input)
}
pub fn qnumber(input: &str) -> TfRes<&str, u32> {
delimited(tag("\""), positive_number, tag("\""))(input)
}
pub fn positive_number(input: &str) -> TfRes<&str, u32> {
ws(map_res(recognize(digit1), |res: &str| u32::from_str(res)))(input)
}
pub fn number(input: &str) -> TfRes<&str, i32> {
ws(map_res(
recognize(pair(opt(alt((tag("+"), tag("-")))), digit1)),
|res: &str| i32::from_str(res),
))(input)
}
pub fn float(input: &str) -> TfRes<&str, f32> {
ws(map_res(
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)))),
recognize(decimal), )),
|res: &str| f32::from_str(res),
))(input)
}
pub fn decimal(input: &str) -> TfRes<&str, &str> {
recognize(many1(terminated(one_of("0123456789"), many0(char('_')))))(input)
}
pub fn boolean_number(input: &str) -> TfRes<&str, bool> {
map(number, |res| match res {
0 => false,
1 => true,
_ => unreachable!(),
})(input)
}
pub fn float_list(input: &str) -> TfRes<&str, Vec<f32>> {
delimited(ws(tag("(")), separated_list1(tag(","), float), ws(tag(")")))(input)
}
pub fn number_list(input: &str) -> TfRes<&str, Vec<u32>> {
delimited(
ws(tag("(")),
separated_list1(tag(","), positive_number),
ws(tag(")")),
)(input)
}
pub fn number_qlist(input: &str) -> TfRes<&str, Vec<u32>> {
delimited(
ws(tag("\"")),
separated_list1(tag(","), positive_number),
ws(tag("\"")),
)(input)
}
pub fn tf_comment(input: &str) -> TfRes<&str, ()> {
value(
(), tuple((ws(tag("/*")), take_until("*/"), ws(tag("*/")))),
)(input)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_comment() {
let input = "
/* Date: Oct.08.2012 */";
let (_, _) = tf_comment(input).unwrap();
}
}