From 128825f148d6415b8c0f7afc3ed4580c2859a627 Mon Sep 17 00:00:00 2001 From: PoiScript Date: Fri, 11 Jan 2019 22:35:06 +0800 Subject: [PATCH] refactor: cleanup --- Cargo.toml | 1 + src/headline.rs | 6 +-- src/lib.rs | 3 ++ src/objects/emphasis.rs | 6 +-- src/objects/macros.rs | 6 ++- src/objects/mod.rs | 110 ++++++++++++++++------------------------ src/objects/snippet.rs | 8 ++- src/parser.rs | 46 ++++++++--------- src/utils.rs | 2 +- 9 files changed, 87 insertions(+), 101 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f5beb93..149608e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" authors = ["PoiScript "] [dependencies] +jetscii = "0.4.3" diff --git a/src/headline.rs b/src/headline.rs index 308143a..8497cb5 100644 --- a/src/headline.rs +++ b/src/headline.rs @@ -112,14 +112,14 @@ impl<'a> Headline<'a> { // TODO: optimize pub fn find_level(src: &str, level: usize) -> usize { let mut pos = 0; - 'outer: loop { + loop { if pos >= src.len() { return src.len(); } if src.as_bytes()[pos] == b'*' && (pos == 0 || src.as_bytes()[pos - 1] == b'\n') { let pos_ = pos; - 'inner: loop { + loop { if pos >= src.len() { return src.len(); } @@ -128,7 +128,7 @@ impl<'a> Headline<'a> { } else if src.as_bytes()[pos] == b' ' && pos - pos_ <= level { return pos_; } else { - break 'inner; + break; } } } diff --git a/src/lib.rs b/src/lib.rs index e2940e9..1f4bfc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,6 @@ +#[macro_use] +extern crate jetscii; + #[macro_use] mod utils; diff --git a/src/objects/emphasis.rs b/src/objects/emphasis.rs index 2c0d6c8..7b2d419 100644 --- a/src/objects/emphasis.rs +++ b/src/objects/emphasis.rs @@ -29,14 +29,14 @@ impl Emphasis { || ch == b'}'); } - Some(end - 1) + Some(end) } } #[test] fn parse() { - assert_eq!(Emphasis::parse("*bold*", b'*').unwrap(), "bold".len()); - assert_eq!(Emphasis::parse("*bo\nld*", b'*').unwrap(), "bo\nld".len()); + assert_eq!(Emphasis::parse("*bold*", b'*').unwrap(), "*bold".len()); + assert_eq!(Emphasis::parse("*bo\nld*", b'*').unwrap(), "*bo\nld".len()); assert!(Emphasis::parse("*bold*a", b'*').is_none()); assert!(Emphasis::parse("*bold*", b'/').is_none()); assert!(Emphasis::parse("*bold *", b'*').is_none()); diff --git a/src/objects/macros.rs b/src/objects/macros.rs index 95553d9..c00db66 100644 --- a/src/objects/macros.rs +++ b/src/objects/macros.rs @@ -1,3 +1,5 @@ +use jetscii::Substring; + #[cfg_attr(test, derive(PartialEq, Debug))] pub struct Macros<'a> { pub name: &'a str, @@ -27,12 +29,12 @@ impl<'a> Macros<'a> { name + 3, )) } else { - let end = &src[name..].find("}}}").map(|i| i + name)?; + let end = Substring::new("}}}").find(&src[name..]).map(|i| i + name)?; expect!(src, end - 1, b')')?; Some(( Macros { name: &src[3..name], - args: if name == *end { + args: if name == end { None } else { Some(&src[name + 1..end - 1]) diff --git a/src/objects/mod.rs b/src/objects/mod.rs index 4024960..dea4901 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -32,6 +32,7 @@ pub enum Object<'a> { Snippet(Snippet<'a>), Target(Target<'a>), + // `end` indicates the position of the second marker Bold { end: usize }, Italic { end: usize }, Strike { end: usize }, @@ -52,19 +53,13 @@ impl<'a> Object<'a> { // TODO: refactor with src[..].find(..) for pos in 0..src.len() - 2 { - macro_rules! parse { - ($obj:ident) => { - if let Some((obj, off)) = $obj::parse(&src[pos..]) { - return if pos == 0 { - (Object::$obj(obj), off, None) - } else { - ( - Object::Text(&src[0..pos]), - pos, - Some((Object::$obj(obj), off)), - ) - }; - } + macro_rules! ret { + ($obj:expr, $off:expr) => { + return if pos == 0 { + ($obj, $off, None) + } else { + (Object::Text(&src[0..pos]), pos, Some(($obj, $off))) + }; }; } @@ -73,29 +68,43 @@ impl<'a> Object<'a> { let third = bytes[pos + 2]; if first == b'@' && second == b'@' { - parse!(Snippet); + if let Some((snippet, off)) = Snippet::parse(&src[pos..]) { + ret!(Object::Snippet(snippet), off); + } } if first == b'[' { if second == b'f' && third == b'n' { - parse!(FnRef); + if let Some((fn_ref, off)) = FnRef::parse(&src[pos..]) { + ret!(Object::FnRef(fn_ref), off); + } } else if second == b'[' { - parse!(Link); + if let Some((link, off)) = Link::parse(&src[pos..]) { + ret!(Object::Link(link), off); + } } else { - parse!(Cookie); + if let Some((cookie, off)) = Cookie::parse(&src[pos..]) { + ret!(Object::Cookie(cookie), off); + } // TODO: Timestamp } } if first == b'{' && second == b'{' && third == b'{' { - parse!(Macros); + if let Some((macros, off)) = Macros::parse(&src[pos..]) { + ret!(Object::Macros(macros), off); + } } if first == b'<' && second == b'<' { if third == b'<' { - parse!(RadioTarget); + if let Some((target, off)) = RadioTarget::parse(&src[pos..]) { + ret!(Object::RadioTarget(target), off); + } } else if third != b'<' && third != b'\n' { - parse!(Target); + if let Some((target, off)) = Target::parse(&src[pos..]) { + ret!(Object::Target(target), off); + } } } @@ -115,62 +124,29 @@ impl<'a> Object<'a> { || first == b'~') && !second.is_ascii_whitespace() { - if let Some(end) = Emphasis::parse(&src[pos..], first).map(|i| i + pos) { - macro_rules! emph { - ($obj:ident) => { - return if pos == 0 { - (Object::$obj { end }, 1, None) - } else { - ( - Object::Text(&src[0..pos]), - pos, - Some((Object::$obj { end }, end)), - ) - }; - }; - } - + if let Some(end) = Emphasis::parse(&src[pos..], first) { match first { - b'*' => emph!(Bold), - b'+' => emph!(Strike), - b'/' => emph!(Italic), - b'_' => emph!(Underline), - b'~' => { - return if pos == 0 { - (Object::Code(&src[1..end + 1]), end + 2, None) - } else { - ( - Object::Text(&src[0..pos]), - pos, - Some((Object::Code(&src[pos + 1..end + 1]), end - pos + 2)), - ) - }; - } - b'=' => { - return if pos == 0 { - (Object::Verbatim(&src[1..end + 1]), end + 2, None) - } else { - ( - Object::Text(&src[0..pos]), - pos, - Some(( - Object::Verbatim(&src[pos + 1..end + 1]), - end - pos + 2, - )), - ) - }; - } + b'*' => ret!(Object::Bold { end }, 1), + b'+' => ret!(Object::Strike { end }, 1), + b'/' => ret!(Object::Italic { end }, 1), + b'_' => ret!(Object::Underline { end }, 1), + b'~' => ret!(Object::Code(&src[pos + 1..pos + end]), end + 1), + b'=' => ret!(Object::Verbatim(&src[pos + 1..pos + end]), end + 1), _ => unreachable!(), } } } if first == b'c' && second == b'a' && third == b'l' { - parse!(InlineCall); + if let Some((call, off)) = InlineCall::parse(&src[pos..]) { + ret!(Object::InlineCall(call), off); + } } if first == b's' && second == b'r' && third == b'c' { - parse!(InlineSrc); + if let Some((src, off)) = InlineSrc::parse(&src[pos..]) { + ret!(Object::InlineSrc(src), off); + } } } } @@ -182,7 +158,7 @@ impl<'a> Object<'a> { #[test] fn next_2() { // TODO: more tests - assert_eq!(Object::next_2("*bold*"), (Object::Bold { end: 4 }, 1, None)); + assert_eq!(Object::next_2("*bold*"), (Object::Bold { end: 5 }, 1, None)); assert_eq!( Object::next_2("Normal =verbatim="), ( diff --git a/src/objects/snippet.rs b/src/objects/snippet.rs index 6f8897a..6d63616 100644 --- a/src/objects/snippet.rs +++ b/src/objects/snippet.rs @@ -1,3 +1,5 @@ +use jetscii::Substring; + #[cfg_attr(test, derive(PartialEq, Debug))] pub struct Snippet<'a> { pub name: &'a str, @@ -14,12 +16,14 @@ impl<'a> Snippet<'a> { return None; } - let end = &src[name + 1..].find("@@").map(|i| i + name + 1)?; + let end = Substring::new("@@") + .find(&src[name + 1..]) + .map(|i| i + name + 1)?; Some(( Snippet { name: &src[2..name], - value: &src[name + 1..*end], + value: &src[name + 1..end], }, end + 2, )) diff --git a/src/parser.rs b/src/parser.rs index 1c71d7b..f855290 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -156,58 +156,56 @@ impl<'a> Parser<'a> { } fn next_ele(&mut self, end: usize) -> Event<'a> { - let (ele, off) = if let Some((ele, off)) = std::mem::replace(&mut self.ele_buf, None) { - (Some(ele), off) - } else { - let (off, ele, next_2) = Element::next_2(&self.text[self.off..end]); - self.ele_buf = next_2; - (ele, off) - }; - - self.off += off; + let (ele, off) = self + .ele_buf + .take() + .map(|(ele, off)| (Some(ele), off)) + .unwrap_or_else(|| { + let (off, ele, next_2) = Element::next_2(&self.text[self.off..end]); + self.ele_buf = next_2; + (ele, off) + }); if let Some(ele) = ele { match ele { Element::Paragraph { end, trailing } => self.stack.push(Container::Paragraph { - end: end + self.off - off, - trailing: trailing + self.off - off, + end: end + self.off, + trailing: trailing + self.off, }), Element::QuoteBlock { end, content_end, .. } => self.stack.push(Container::QuoteBlock { - content_end: content_end + self.off - off, - end: end + self.off - off, + content_end: content_end + self.off, + end: end + self.off, }), Element::CenterBlock { end, content_end, .. } => self.stack.push(Container::CenterBlock { - content_end: content_end + self.off - off, - end: end + self.off - off, + content_end: content_end + self.off, + end: end + self.off, }), Element::SpecialBlock { end, content_end, .. } => self.stack.push(Container::SpecialBlock { - content_end: content_end + self.off - off, - end: end + self.off - off, + content_end: content_end + self.off, + end: end + self.off, }), _ => (), } + self.off += off; ele.into() } else { + self.off += off; self.end() } } fn next_obj(&mut self, end: usize) -> Event<'a> { - let (obj, off) = if let Some((obj, off)) = std::mem::replace(&mut self.obj_buf, None) { - (obj, off) - } else { + let (obj, off) = self.obj_buf.take().unwrap_or_else(|| { let (obj, off, next_2) = Object::next_2(&self.text[self.off..end]); self.obj_buf = next_2; (obj, off) - }; - - self.off += off; + }); match obj { Object::Underline { end } => self.stack.push(Container::Underline { @@ -225,6 +223,8 @@ impl<'a> Parser<'a> { _ => (), } + self.off += off; + obj.into() } diff --git a/src/utils.rs b/src/utils.rs index ee8662a..d61cb1b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,4 @@ -//! Until macros +//! Utils macros #[macro_export] macro_rules! expect {