diff --git a/Cargo.toml b/Cargo.toml index 4b2ecb3..8a211b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ heapless = "0.6.1" [dependencies.nom] default-features = false -version = "4.2.3" +version = "7.1.3" [features] default = ["std"] diff --git a/src/parsers.rs b/src/parsers.rs index b0bf613..76aef6a 100644 --- a/src/parsers.rs +++ b/src/parsers.rs @@ -3,237 +3,170 @@ mod tests; use crate::AnsiSequence; -use core::convert::TryInto; use heapless::Vec; -use nom::*; +use nom::branch::alt; +use nom::bytes::complete::tag; +use nom::character::complete::{digit0, digit1}; +use nom::combinator::{map, map_res, opt, value}; +use nom::sequence::{delimited, preceded, tuple}; +use nom::IResult; macro_rules! tag_parser { ($sig:ident, $tag:expr, $ret:expr) => { - named!( - $sig<&str, AnsiSequence>, - do_parse!( - tag!($tag) >> - ($ret) - ) - ); - } + fn $sig(input: &str) -> IResult<&str, AnsiSequence> { + value($ret, tag($tag))(input) + } + }; } -named!( - parse_int<&str, u32>, - map_res!( - nom::digit, - |s: &str| s.parse::() - ) -); +fn parse_u32(input: &str) -> IResult<&str, u32> { + map_res(digit1, |s: &str| s.parse::())(input) +} + +fn parse_u8(input: &str) -> IResult<&str, u8> { + map_res(digit1, |s: &str| s.parse::())(input) +} // TODO kind of ugly, would prefer to pass in the default so we could use it for // all escapes with defaults (not just those that default to 1). -named!( - parse_def_cursor_int<&str, u32>, - map!( - nom::digit0, - |s: &str| s.parse::().unwrap_or(1) - ) -); +fn parse_def_cursor_int(input: &str) -> IResult<&str, u32> { + map(digit0, |s: &str| s.parse::().unwrap_or(1))(input) +} -named!( - cursor_pos<&str, AnsiSequence>, - do_parse!( - tag!("[") >> - x: parse_def_cursor_int >> - opt!(tag!(";")) >> - y: parse_def_cursor_int >> - alt!( - tag!("H") | - tag!("f") - ) >> - (AnsiSequence::CursorPos(x, y)) - ) -); +fn cursor_pos(input: &str) -> IResult<&str, AnsiSequence> { + map( + tuple(( + tag("["), + parse_def_cursor_int, + opt(tag(";")), + parse_def_cursor_int, + alt((tag("H"), tag("f"))), + )), + |(_, x, _, y, _)| AnsiSequence::CursorPos(x, y), + )(input) +} -named!( - escape<&str, AnsiSequence>, - do_parse!( - tag!("\u{1b}") >> - (AnsiSequence::Escape) - ) -); +fn escape(input: &str) -> IResult<&str, AnsiSequence> { + value(AnsiSequence::Escape, tag("\u{1b}"))(input) +} -named!( - cursor_up<&str, AnsiSequence>, - do_parse!( - tag!("[") >> - am: parse_def_cursor_int >> - tag!("A") >> - (AnsiSequence::CursorUp(am)) - ) -); +fn cursor_up(input: &str) -> IResult<&str, AnsiSequence> { + map(delimited(tag("["), parse_def_cursor_int, tag("A")), |am| { + AnsiSequence::CursorUp(am) + })(input) +} -named!( - cursor_down<&str, AnsiSequence>, - do_parse!( - tag!("[") >> - am: parse_def_cursor_int >> - tag!("B") >> - (AnsiSequence::CursorDown(am)) - ) -); +fn cursor_down(input: &str) -> IResult<&str, AnsiSequence> { + map(delimited(tag("["), parse_def_cursor_int, tag("B")), |am| { + AnsiSequence::CursorDown(am) + })(input) +} -named!( - cursor_forward<&str, AnsiSequence>, - do_parse!( - tag!("[") >> - am: parse_def_cursor_int >> - tag!("C") >> - (AnsiSequence::CursorForward(am)) - ) -); +fn cursor_forward(input: &str) -> IResult<&str, AnsiSequence> { + map(delimited(tag("["), parse_def_cursor_int, tag("C")), |am| { + AnsiSequence::CursorForward(am) + })(input) +} -named!( - cursor_backward<&str, AnsiSequence>, - do_parse!( - tag!("[") >> - am: parse_def_cursor_int >> - tag!("D") >> - (AnsiSequence::CursorBackward(am)) - ) -); +fn cursor_backward(input: &str) -> IResult<&str, AnsiSequence> { + map(delimited(tag("["), parse_def_cursor_int, tag("D")), |am| { + AnsiSequence::CursorBackward(am) + })(input) +} -named!( - graphics_mode1<&str, AnsiSequence>, - do_parse!( - tag!("[") >> - val: parse_int >> - tag!("m") >> - val: expr_res!(val.try_into()) >> - conv: expr_res!(Vec::from_slice(&[val])) >> - (AnsiSequence::SetGraphicsMode(conv)) - ) -); +fn graphics_mode1(input: &str) -> IResult<&str, AnsiSequence> { + map(delimited(tag("["), parse_u8, tag("m")), |val| { + let mode = + Vec::from_slice(&[val]).expect("Vec::from_slice should allocate sufficient size"); + AnsiSequence::SetGraphicsMode(mode) + })(input) +} -named!( - graphics_mode2<&str, AnsiSequence>, - do_parse!( - tag!("[") >> - val1: parse_int >> - tag!(";") >> - val2: parse_int >> - tag!("m") >> - val1: expr_res!(val1.try_into()) >> - val2: expr_res!(val2.try_into()) >> - conv: expr_res!(Vec::from_slice(&[ - val1, - val2, - ])) >> - (AnsiSequence::SetGraphicsMode(conv)) - ) -); +fn graphics_mode2(input: &str) -> IResult<&str, AnsiSequence> { + map( + tuple((tag("["), parse_u8, tag(";"), parse_u8, tag("m"))), + |(_, val1, _, val2, _)| { + let mode = Vec::from_slice(&[val1, val2]) + .expect("Vec::from_slice should allocate sufficient size"); + AnsiSequence::SetGraphicsMode(mode) + }, + )(input) +} -named!( - graphics_mode3<&str, AnsiSequence>, - do_parse!( - tag!("[") >> - val1: parse_int >> - tag!(";") >> - val2: parse_int >> - tag!(";") >> - val3: parse_int >> - tag!("m") >> - val1: expr_res!(val1.try_into()) >> - val2: expr_res!(val2.try_into()) >> - val3: expr_res!(val3.try_into()) >> - conv: expr_res!(Vec::from_slice(&[ - val1, - val2, - val3, - ])) >> - (AnsiSequence::SetGraphicsMode(conv)) - ) -); +fn graphics_mode3(input: &str) -> IResult<&str, AnsiSequence> { + map( + tuple(( + tag("["), + parse_u8, + tag(";"), + parse_u8, + tag(";"), + parse_u8, + tag("m"), + )), + |(_, val1, _, val2, _, val3, _)| { + let mode = Vec::from_slice(&[val1, val2, val3]) + .expect("Vec::from_slice should allocate sufficient size"); + AnsiSequence::SetGraphicsMode(mode) + }, + )(input) +} -named!( - graphics_mode4<&str, AnsiSequence>, - do_parse!( - tag!("[m") >> - (AnsiSequence::SetGraphicsMode(Vec::new())) - ) -); +fn graphics_mode4(input: &str) -> IResult<&str, AnsiSequence> { + value(AnsiSequence::SetGraphicsMode(Vec::new()), tag("[m"))(input) +} -named!( - graphics_mode5<&str, AnsiSequence>, - do_parse!( - tag!("[") >> - val1: parse_int >> - tag!(";") >> - val2: parse_int >> - tag!(";") >> - val3: parse_int >> - tag!(";") >> - val4: parse_int >> - tag!(";") >> - val5: parse_int >> - tag!("m") >> - val1: expr_res!(val1.try_into()) >> - val2: expr_res!(val2.try_into()) >> - val3: expr_res!(val3.try_into()) >> - val4: expr_res!(val4.try_into()) >> - val5: expr_res!(val5.try_into()) >> - conv: expr_res!(Vec::from_slice(&[ - val1, - val2, - val3, - val4, - val5, - ])) >> - (AnsiSequence::SetGraphicsMode(conv)) - ) -); +fn graphics_mode5(input: &str) -> IResult<&str, AnsiSequence> { + map( + tuple(( + tag("["), + parse_u8, + tag(";"), + parse_u8, + tag(";"), + parse_u8, + tag(";"), + parse_u8, + tag(";"), + parse_u8, + tag("m"), + )), + |(_, val1, _, val2, _, val3, _, val4, _, val5, _)| { + let mode = Vec::from_slice(&[val1, val2, val3, val4, val5]) + .expect("Vec::from_slice should allocate sufficient size"); + AnsiSequence::SetGraphicsMode(mode) + }, + )(input) +} -named!( - graphics_mode<&str, AnsiSequence>, - alt!( - graphics_mode1 - | graphics_mode2 - | graphics_mode3 - | graphics_mode4 - | graphics_mode5 - ) -); +fn graphics_mode(input: &str) -> IResult<&str, AnsiSequence> { + alt(( + graphics_mode1, + graphics_mode2, + graphics_mode3, + graphics_mode4, + graphics_mode5, + ))(input) +} -named!( - set_mode<&str, AnsiSequence>, - do_parse!( - tag!("[=") >> - mode: parse_int >> - conv: expr_res!(mode.try_into()) >> - tag!("h") >> - (AnsiSequence::SetMode(conv)) - ) -); +fn set_mode(input: &str) -> IResult<&str, AnsiSequence> { + map(delimited(tag("[="), parse_u8, tag("h")), |val| { + AnsiSequence::SetMode(val) + })(input) +} -named!( - reset_mode<&str, AnsiSequence>, - do_parse!( - tag!("[=") >> - mode: parse_int >> - conv: expr_res!(mode.try_into()) >> - tag!("l") >> - (AnsiSequence::ResetMode(conv)) - ) -); +fn reset_mode(input: &str) -> IResult<&str, AnsiSequence> { + map(delimited(tag("[="), parse_u8, tag("l")), |val| { + AnsiSequence::ResetMode(val) + })(input) +} -named!( - set_top_and_bottom<&str, AnsiSequence>, - do_parse!( - tag!("[") >> - x: parse_int >> - tag!(";") >> - y: parse_int >> - tag!("r") >> - (AnsiSequence::SetTopAndBottom(x, y)) - ) -); +fn set_top_and_bottom(input: &str) -> IResult<&str, AnsiSequence> { + map( + tuple((tag("["), parse_u32, tag(";"), parse_u32, tag("r"))), + |(_, x, _, y, _)| AnsiSequence::SetTopAndBottom(x, y), + )(input) +} tag_parser!(cursor_save, "[s", AnsiSequence::CursorSave); tag_parser!(cursor_restore, "[u", AnsiSequence::CursorRestore); @@ -276,66 +209,67 @@ tag_parser!(set_g1_graph, ")2", AnsiSequence::SetG1AltAndSpecialGraph); tag_parser!(set_single_shift2, "N", AnsiSequence::SetSingleShift2); tag_parser!(set_single_shift3, "O", AnsiSequence::SetSingleShift3); -named!( - combined<&str, AnsiSequence>, - alt!( - escape - | cursor_pos - | cursor_up - | cursor_down - | cursor_forward - | cursor_backward - | cursor_save - | cursor_restore - | erase_display - | erase_line - | graphics_mode - | set_mode - | reset_mode - | hide_cursor - | show_cursor - | cursor_to_app - | set_new_line_mode - | set_col_132 - | set_smooth_scroll - | set_reverse_video - | set_origin_rel - | set_auto_wrap - | set_auto_repeat - | set_interlacing - | set_linefeed - | set_cursorkey - | set_vt52 - | set_col80 - | set_jump_scroll - | set_normal_video - | set_origin_abs - | reset_auto_wrap - | reset_auto_repeat - | reset_interlacing - | set_top_and_bottom - | set_alternate_keypad - | set_numeric_keypad - | set_uk_g0 - | set_uk_g1 - | set_us_g0 - | set_us_g1 - | set_g0_special - | set_g1_special - | set_g0_alternate - | set_g1_alternate - | set_g0_graph - | set_g1_graph - | set_single_shift2 - | set_single_shift3 - ) -); +fn combined(input: &str) -> IResult<&str, AnsiSequence> { + // `alt` only supports up to 21 parsers, and nom doesn't seem to + // have an alternative with higher variability. + // So we simply nest them. + alt(( + alt(( + escape, + cursor_pos, + cursor_up, + cursor_down, + cursor_forward, + cursor_backward, + cursor_save, + cursor_restore, + erase_display, + erase_line, + graphics_mode, + set_mode, + reset_mode, + hide_cursor, + show_cursor, + cursor_to_app, + set_new_line_mode, + set_col_132, + set_smooth_scroll, + set_reverse_video, + set_origin_rel, + )), + alt(( + set_auto_wrap, + set_auto_repeat, + set_interlacing, + set_linefeed, + set_cursorkey, + set_vt52, + set_col80, + set_jump_scroll, + set_normal_video, + set_origin_abs, + reset_auto_wrap, + reset_auto_repeat, + reset_interlacing, + set_top_and_bottom, + set_alternate_keypad, + set_numeric_keypad, + set_uk_g0, + set_uk_g1, + set_us_g0, + set_us_g1, + set_g0_special, + )), + set_g1_special, + set_g0_alternate, + set_g1_alternate, + set_g0_graph, + set_g1_graph, + set_single_shift2, + set_single_shift3, + ))(input) +} -named!( - pub parse_escape<&str, AnsiSequence>, - do_parse!( - tag!("\u{1b}") >> - seq: combined >> - (seq) - ) -); +pub fn parse_escape(input: &str) -> IResult<&str, AnsiSequence> { + preceded(tag("\u{1b}"), combined)(input) +}