use nom::IResult; use nom::number::complete::be_u16; use nom::bytes::complete::{take, is_not, take_while, escaped}; use nom::character::complete::{char, one_of}; use nom::bytes::complete::{take_while1, tag, take_while_m_n}; use nom::combinator::{map_res, opt, cut}; use nom::sequence::{preceded, tuple, delimited, terminated}; use nom::error::ParseError; use nom::character::complete::{alphanumeric1 as alphanumeric}; 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 struct ScriptMeta { } 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, u8> { let (input, _) = tag("elem")(input)?; let input = sp(input)?; Ok((input.0, 0)) } pub fn comment<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, u8, E> { preceded(char('#'), cut(terminated(escaped( alphanumeric, '\\', one_of("\"n\\")), char('\"'))) )(input)?; // let (input, _) = tag("#")(input)?; Ok(("", 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> { if let Ok(v) = elem_tag(input) { println!("Found elem tag"); if let Ok(v) = sp(v.0) { preceded(sp, char(':')); println!("ate some spaces"); } else { println!("didn't eat spaces?"); } } if let Ok(v) = comment(input) { println!("Found comment tag") } return Ok(("", ScriptMeta{})) } /* // ( 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()); */