use nom::branch::alt; use nom::bytes::complete::{escaped, is_not, take, take_till, take_until, take_while}; use nom::bytes::complete::{tag, take_while1, take_while_m_n}; use nom::character::complete::{char, one_of, newline, not_line_ending, anychar}; use nom::character::complete::alphanumeric1 as alphanumeric; use nom::combinator::{cut, map, map_res, opt}; use nom::error::ParseError; use nom::IResult; use nom::number::complete::be_u16; use nom::sequence::{delimited, preceded, terminated, tuple}; pub fn length_value(input: &[u8]) -> IResult<&[u8], &[u8]> { let (input, length) = be_u16(input)?; take(length)(input) } #[derive(Debug, PartialEq)] pub struct Color { pub red: u8, pub green: u8, pub blue: u8, } pub enum ScriptMeta { Comment(String), Element(String), Meta(String), } pub fn from_hex(input: &str) -> Result { u8::from_str_radix(input, 16) } pub fn is_hex_digit(c: char) -> bool { c.is_digit(16) } pub fn hex_primary(input: &str) -> IResult<&str, u8> { map_res( take_while_m_n(2, 2, is_hex_digit), from_hex, )(input) } pub fn hex_color(input: &str) -> IResult<&str, Color> { let (input, _) = tag("#")(input)?; let (input, (red, green, blue)) = tuple((hex_primary, hex_primary, hex_primary))(input)?; Ok((input, Color { red, green, blue })) } pub fn elem_tag(input: &str) -> IResult<&str, &str> { let (input, _) = tag("elem")(input)?; let input = sp(input)?; Ok((input.0, input.0)) } fn parse_str<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> { let chars = "\n"; escaped(anychar, '\\', one_of(""))(i) } pub fn comment<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, &'a str, E> { // if let Ok(t) = preceded(sp, char('#'))(input) { // let v = take_until("\n")(t.0).unwrap(); // println!("{:?}", t); // } let v = preceded(char('#'), cut( terminated( parse_str, newline, ) ), )(input)?; println!("{:?}", v); Ok((v.0, v.0)) } fn curlies(input: &str) -> IResult<&str, &str> { delimited(char('{'), is_not("}"), char('}'))(input) } /// parser combinators are constructed from the bottom up: /// first we write parsers for the smallest elements (here a space character), /// then we'll combine them in larger parsers fn sp<'a>(i: &'a str) -> IResult<&'a str, &'a str> { let chars = " \t\r\n"; // nom combinators like `take_while` return a function. That function is the // parser,to which we can pass the input take_while(move |c| chars.contains(c))(i) } pub fn parse_script<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, ScriptMeta, E> { let x = delimited( sp, alt((map(comment, |s| ScriptMeta::Comment(String::from(s))), map(elem_tag, |s| ScriptMeta::Element(String::from(s))) )), opt(sp), )(input); // if let Ok(v) = elem_tag(input) { // println!("Found elem tag"); // if let Ok(v) = sp(v.0) { // // println!("ate some spaces"); // } // else { // println!("didn't eat spaces?"); // } // } // if let Ok(v) = comment(input) { // println!("Found comment tag") // } let x = x.unwrap().0; return Ok((x, ScriptMeta::Comment(String::default()))); } /* // ( and any amount of bytes ). Returns the bytes between the () fn parens(input: &str) -> IResult<&str, &str> { delimited(char('('), is_not(")"), char(')'))(input) } // `take_while_m_n` parses between `m` and `n` bytes (inclusive) that match // a predicate. `parse_hex` here parses between 1 and 6 hexadecimal numerals. let parse_hex = take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit()); */