refactor(elements): add Element::Empty variant

This commit is contained in:
PoiScript 2019-02-16 15:39:28 +08:00
parent c7de340479
commit 74a19c2ff7
2 changed files with 48 additions and 47 deletions

View file

@ -76,16 +76,19 @@ pub enum Element<'a> {
ident: usize, ident: usize,
ordered: bool, ordered: bool,
}, },
// Element::Empty actually means Option<Element>::None
Empty,
} }
// return (element, off, next element, next offset) // return (element, off, next element, next offset)
// the end of first element is relative to the offset // the end of first element is relative to the offset
// next offset is relative to the end of the first element // next offset is relative to the end of the first element
pub fn parse(src: &str) -> (Option<Element<'_>>, usize, Option<(Element<'_>, usize)>) { pub fn parse(src: &str) -> (Element<'_>, usize, Option<(Element<'_>, usize)>) {
// skip empty lines // skip empty lines
let mut pos = match src.chars().position(|c| c != '\n') { let mut pos = match src.chars().position(|c| c != '\n') {
Some(pos) => pos, Some(pos) => pos,
None => return (None, src.len(), None), None => return (Element::Empty, src.len(), None),
}; };
let start = pos; let start = pos;
let bytes = src.as_bytes(); let bytes = src.as_bytes();
@ -97,13 +100,13 @@ pub fn parse(src: &str) -> (Option<Element<'_>>, usize, Option<(Element<'_>, usi
macro_rules! brk { macro_rules! brk {
($ele:expr, $off:expr) => { ($ele:expr, $off:expr) => {
break if line_beg == start || pos == start { break if line_beg == start || pos == start {
(Some($ele), pos + $off, None) ($ele, pos + $off, None)
} else { } else {
( (
Some(Element::Paragraph { Element::Paragraph {
cont_end: line_beg - start - 1, cont_end: line_beg - start - 1,
end: line_beg - start, end: line_beg - start,
}), },
start, start,
Some(($ele, $off)), Some(($ele, $off)),
) )
@ -120,10 +123,10 @@ pub fn parse(src: &str) -> (Option<Element<'_>>, usize, Option<(Element<'_>, usi
if bytes[pos] == b'\n' { if bytes[pos] == b'\n' {
break ( break (
Some(Element::Paragraph { Element::Paragraph {
cont_end: pos - start - 1, cont_end: pos - start - 1,
end: pos - start + 1, end: pos - start + 1,
}), },
start, start,
None, None,
); );
@ -138,13 +141,13 @@ pub fn parse(src: &str) -> (Option<Element<'_>>, usize, Option<(Element<'_>, usi
ordered, ordered,
}; };
break if line_beg == start { break if line_beg == start {
(Some(list), start, None) (list, start, None)
} else { } else {
( (
Some(Element::Paragraph { Element::Paragraph {
cont_end: line_beg - start - 1, cont_end: line_beg - start - 1,
end: line_beg - start, end: line_beg - start,
}), },
start, start,
Some((list, 0)), Some((list, 0)),
) )
@ -247,20 +250,20 @@ pub fn parse(src: &str) -> (Option<Element<'_>>, usize, Option<(Element<'_>, usi
// the last character // the last character
if pos >= src.len() { if pos >= src.len() {
break ( break (
Some(Element::Paragraph { Element::Paragraph {
cont_end: src.len() - start - 1, cont_end: src.len() - start - 1,
end: src.len() - start, end: src.len() - start,
}), },
start, start,
None, None,
); );
} }
} else { } else {
break ( break (
Some(Element::Paragraph { Element::Paragraph {
cont_end: src.len() - start, cont_end: src.len() - start,
end: src.len() - start, end: src.len() - start,
}), },
start, start,
None, None,
); );
@ -272,18 +275,20 @@ pub fn parse(src: &str) -> (Option<Element<'_>>, usize, Option<(Element<'_>, usi
mod tests { mod tests {
#[test] #[test]
fn parse() { fn parse() {
use super::{Element::*, *}; use super::keyword::Key;
use super::parse;
use super::Element::*;
assert_eq!(parse("\n\n\n"), (None, 3, None)); assert_eq!(parse("\n\n\n"), (Empty, 3, None));
let len = "Lorem ipsum dolor sit amet.".len(); let len = "Lorem ipsum dolor sit amet.".len();
assert_eq!( assert_eq!(
parse("\nLorem ipsum dolor sit amet.\n\n\n"), parse("\nLorem ipsum dolor sit amet.\n\n\n"),
( (
Some(Paragraph { Paragraph {
cont_end: len, cont_end: len,
end: len + 2, end: len + 2,
}), },
1, 1,
None None
) )
@ -291,10 +296,10 @@ mod tests {
assert_eq!( assert_eq!(
parse("\n\nLorem ipsum dolor sit amet.\n\n"), parse("\n\nLorem ipsum dolor sit amet.\n\n"),
( (
Some(Paragraph { Paragraph {
cont_end: len, cont_end: len,
end: len + 2, end: len + 2,
}), },
2, 2,
None None
) )
@ -302,10 +307,10 @@ mod tests {
assert_eq!( assert_eq!(
parse("\nLorem ipsum dolor sit amet.\n"), parse("\nLorem ipsum dolor sit amet.\n"),
( (
Some(Paragraph { Paragraph {
cont_end: len, cont_end: len,
end: len + 1, end: len + 1,
}), },
1, 1,
None None
) )
@ -313,10 +318,10 @@ mod tests {
assert_eq!( assert_eq!(
parse("\n\n\nLorem ipsum dolor sit amet."), parse("\n\n\nLorem ipsum dolor sit amet."),
( (
Some(Paragraph { Paragraph {
cont_end: len, cont_end: len,
end: len, end: len,
}), },
3, 3,
None None
) )
@ -325,7 +330,7 @@ mod tests {
assert_eq!( assert_eq!(
parse("\n\n\n: Lorem ipsum dolor sit amet.\n"), parse("\n\n\n: Lorem ipsum dolor sit amet.\n"),
( (
Some(FixedWidth("Lorem ipsum dolor sit amet.")), FixedWidth("Lorem ipsum dolor sit amet."),
"\n\n\n: Lorem ipsum dolor sit amet.\n".len(), "\n\n\n: Lorem ipsum dolor sit amet.\n".len(),
None None
) )
@ -333,7 +338,7 @@ mod tests {
assert_eq!( assert_eq!(
parse("\n\n\n: Lorem ipsum dolor sit amet."), parse("\n\n\n: Lorem ipsum dolor sit amet."),
( (
Some(FixedWidth("Lorem ipsum dolor sit amet.")), FixedWidth("Lorem ipsum dolor sit amet."),
"\n\n\n: Lorem ipsum dolor sit amet.".len(), "\n\n\n: Lorem ipsum dolor sit amet.".len(),
None None
) )
@ -342,10 +347,10 @@ mod tests {
assert_eq!( assert_eq!(
parse("\n\nLorem ipsum dolor sit amet.\n: Lorem ipsum dolor sit amet.\n"), parse("\n\nLorem ipsum dolor sit amet.\n: Lorem ipsum dolor sit amet.\n"),
( (
Some(Paragraph { Paragraph {
cont_end: len, cont_end: len,
end: len + 1, end: len + 1,
}), },
2, 2,
Some((FixedWidth("Lorem ipsum dolor sit amet."), 30)) Some((FixedWidth("Lorem ipsum dolor sit amet."), 30))
) )
@ -354,10 +359,10 @@ mod tests {
assert_eq!( assert_eq!(
parse("\n\nLorem ipsum dolor sit amet.\n+ Lorem ipsum dolor sit amet.\n"), parse("\n\nLorem ipsum dolor sit amet.\n+ Lorem ipsum dolor sit amet.\n"),
( (
Some(Paragraph { Paragraph {
cont_end: len, cont_end: len,
end: len + 1, end: len + 1,
}), },
2, 2,
Some(( Some((
List { List {
@ -372,10 +377,10 @@ mod tests {
assert_eq!( assert_eq!(
parse("\n\nLorem ipsum dolor sit amet.\n#+BEGIN_QUOTE\nLorem ipsum dolor sit amet.\n#+END_QUOTE\n"), parse("\n\nLorem ipsum dolor sit amet.\n#+BEGIN_QUOTE\nLorem ipsum dolor sit amet.\n#+END_QUOTE\n"),
( (
Some(Paragraph { Paragraph {
cont_end: len, cont_end: len,
end: len + 1, end: len + 1,
}), },
2, 2,
Some(( Some((
QteBlock { QteBlock {
@ -390,10 +395,10 @@ mod tests {
assert_eq!( assert_eq!(
parse("\n #+ATTR_HTML: :width 200px"), parse("\n #+ATTR_HTML: :width 200px"),
( (
Some(Keyword { Keyword {
key: keyword::Key::Attr { backend: "HTML" }, key: Key::Attr { backend: "HTML" },
value: ":width 200px" value: ":width 200px"
}), },
"\n #+ATTR_HTML: :width 200px".len(), "\n #+ATTR_HTML: :width 200px".len(),
None None
) )

View file

@ -261,11 +261,7 @@ impl<'a> Parser<'a> {
fn next_ele(&mut self, end: usize) -> Event<'a> { fn next_ele(&mut self, end: usize) -> Event<'a> {
let text = &self.text[self.off..end]; let text = &self.text[self.off..end];
let (ele, off) = self let (ele, off) = self.ele_buf.take().unwrap_or_else(|| {
.ele_buf
.take()
.map(|(ele, off)| (Some(ele), off))
.unwrap_or_else(|| {
let (ele, off, next_ele) = elements::parse(text); let (ele, off, next_ele) = elements::parse(text);
self.ele_buf = next_ele; self.ele_buf = next_ele;
(ele, off) (ele, off)
@ -275,7 +271,7 @@ impl<'a> Parser<'a> {
self.off += off; self.off += off;
ele.map(|x| match x { match ele {
Element::Paragraph { cont_end, end } => { Element::Paragraph { cont_end, end } => {
debug_assert!(cont_end <= text.len() && end <= text.len()); debug_assert!(cont_end <= text.len() && end <= text.len());
self.stack.push(Container::Paragraph { self.stack.push(Container::Paragraph {
@ -346,8 +342,8 @@ impl<'a> Parser<'a> {
Element::Rule => Event::Rule, Element::Rule => Event::Rule,
Element::SrcBlock { args, cont } => Event::SrcBlock { args, cont }, Element::SrcBlock { args, cont } => Event::SrcBlock { args, cont },
Element::VerseBlock { args, cont } => Event::VerseBlock { args, cont }, Element::VerseBlock { args, cont } => Event::VerseBlock { args, cont },
}) Element::Empty => self.end(),
.unwrap_or_else(|| self.end()) }
} }
fn next_obj(&mut self, end: usize) -> Event<'a> { fn next_obj(&mut self, end: usize) -> Event<'a> {