refactor(parser): redesign stack structure

This commit is contained in:
PoiScript 2019-03-17 02:07:31 +08:00
parent 0b22db1f0f
commit 7273a2e84d

View file

@ -7,58 +7,19 @@ use crate::objects::{self, *};
#[cfg_attr(test, derive(PartialEq))] #[cfg_attr(test, derive(PartialEq))]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
enum Container { enum Container {
Headline { Headline(usize),
beg: usize, Section,
end: usize, Paragraph,
}, CtrBlock,
Section { QteBlock,
end: usize, SplBlock,
}, DynBlock,
Paragraph { List(usize, bool),
cont_end: usize, ListItem,
end: usize, Italic,
}, Strike,
CtrBlock { Bold,
cont_end: usize, Underline,
end: usize,
},
QteBlock {
cont_end: usize,
end: usize,
},
SplBlock {
cont_end: usize,
end: usize,
},
DynBlock {
cont_end: usize,
end: usize,
},
List {
ident: usize,
ordered: bool,
end: usize,
},
ListItem {
cont_end: usize,
end: usize,
},
Italic {
cont_end: usize,
end: usize,
},
Strike {
cont_end: usize,
end: usize,
},
Bold {
cont_end: usize,
end: usize,
},
Underline {
cont_end: usize,
end: usize,
},
} }
#[cfg_attr(test, derive(PartialEq))] #[cfg_attr(test, derive(PartialEq))]
@ -195,12 +156,13 @@ pub enum Event<'a> {
pub struct Parser<'a> { pub struct Parser<'a> {
text: &'a str, text: &'a str,
stack: Vec<Container>, stack: Vec<(Container, usize, usize)>,
off: usize, off: usize,
ele_buf: Option<(Element<'a>, usize)>, ele_buf: Option<(Element<'a>, usize)>,
obj_buf: Option<(Object<'a>, usize)>, obj_buf: Option<(Object<'a>, usize)>,
has_more_item: bool,
keywords: Option<&'a [&'a str]>, keywords: Option<&'a [&'a str]>,
list_more_item: bool,
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
@ -212,7 +174,7 @@ impl<'a> Parser<'a> {
off: 0, off: 0,
ele_buf: None, ele_buf: None,
obj_buf: None, obj_buf: None,
has_more_item: false, list_more_item: false,
keywords: None, keywords: None,
} }
} }
@ -231,30 +193,30 @@ impl<'a> Parser<'a> {
self.keywords = Some(keywords) self.keywords = Some(keywords)
} }
fn next_sec_or_hdl(&mut self) -> Event<'a> { fn next_section_or_headline(&mut self) -> Event<'a> {
let end = Headline::find_level(&self.text[self.off..], std::usize::MAX); let end = Headline::find_level(&self.text[self.off..], std::usize::MAX);
debug_assert!(end <= self.text[self.off..].len()); debug_assert!(end <= self.text[self.off..].len());
if end != 0 { if end != 0 {
self.stack.push(Container::Section { self.stack
end: self.off + end, .push((Container::Section, self.off + end, self.off + end));
});
Event::SectionBeg Event::SectionBeg
} else { } else {
self.next_hdl() self.next_headline()
} }
} }
fn next_hdl(&mut self) -> Event<'a> { fn next_headline(&mut self) -> Event<'a> {
let (hdl, off, end) = if let Some(keywords) = self.keywords { let (hdl, off, end) = if let Some(keywords) = self.keywords {
Headline::parse_with_keywords(&self.text[self.off..], keywords) Headline::parse_with_keywords(&self.text[self.off..], keywords)
} else { } else {
Headline::parse(&self.text[self.off..]) Headline::parse(&self.text[self.off..])
}; };
debug_assert!(end <= self.text[self.off..].len()); debug_assert!(end <= self.text[self.off..].len());
self.stack.push(Container::Headline { self.stack.push((
beg: self.off + off, Container::Headline(self.off + off),
end: self.off + end, self.off + end,
}); self.off + end,
));
self.off += off; self.off += off;
Event::HeadlineBeg(hdl) Event::HeadlineBeg(hdl)
} }
@ -274,26 +236,20 @@ impl<'a> Parser<'a> {
match ele { 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
cont_end: cont_end + self.off, .push((Container::Paragraph, cont_end + self.off, end + self.off));
end: end + self.off,
});
Event::ParagraphBeg Event::ParagraphBeg
} }
Element::QteBlock { end, cont_end, .. } => { Element::QteBlock { end, cont_end, .. } => {
debug_assert!(cont_end <= text.len() && end <= text.len()); debug_assert!(cont_end <= text.len() && end <= text.len());
self.stack.push(Container::QteBlock { self.stack
cont_end: cont_end + self.off, .push((Container::QteBlock, cont_end + self.off, end + self.off));
end: end + self.off,
});
Event::QteBlockBeg Event::QteBlockBeg
} }
Element::CtrBlock { end, cont_end, .. } => { Element::CtrBlock { end, cont_end, .. } => {
debug_assert!(cont_end <= text.len() && end <= text.len()); debug_assert!(cont_end <= text.len() && end <= text.len());
self.stack.push(Container::CtrBlock { self.stack
cont_end: cont_end + self.off, .push((Container::CtrBlock, cont_end + self.off, end + self.off));
end: end + self.off,
});
Event::CtrBlockBeg Event::CtrBlockBeg
} }
Element::SplBlock { Element::SplBlock {
@ -303,10 +259,8 @@ impl<'a> Parser<'a> {
cont_end, cont_end,
} => { } => {
debug_assert!(cont_end <= text.len() && end <= text.len()); debug_assert!(cont_end <= text.len() && end <= text.len());
self.stack.push(Container::SplBlock { self.stack
cont_end: cont_end + self.off, .push((Container::SplBlock, cont_end + self.off, end + self.off));
end: end + self.off,
});
Event::SplBlockBeg { name, args } Event::SplBlockBeg { name, args }
} }
Element::DynBlock { Element::DynBlock {
@ -316,19 +270,13 @@ impl<'a> Parser<'a> {
end, end,
} => { } => {
debug_assert!(cont_end <= text.len() && end <= text.len()); debug_assert!(cont_end <= text.len() && end <= text.len());
self.stack.push(Container::DynBlock { self.stack
cont_end: cont_end + self.off, .push((Container::DynBlock, cont_end + self.off, end + self.off));
end: end + self.off,
});
Event::DynBlockBeg { name, args } Event::DynBlockBeg { name, args }
} }
Element::List { ident, ordered } => { Element::List { ident, ordered } => {
self.stack.push(Container::List { self.stack.push((Container::List(ident, ordered), end, end));
ident, self.list_more_item = true;
ordered,
end,
});
self.has_more_item = true;
Event::ListBeg { ordered } Event::ListBeg { ordered }
} }
Element::Call { value } => Event::Call { value }, Element::Call { value } => Event::Call { value },
@ -361,34 +309,26 @@ impl<'a> Parser<'a> {
match obj { match obj {
Object::Underline { end } => { Object::Underline { end } => {
debug_assert!(end <= text.len()); debug_assert!(end <= text.len());
self.stack.push(Container::Underline { self.stack
cont_end: self.off + end - 1, .push((Container::Underline, end + self.off - 1, end + self.off));
end: self.off + end,
});
Event::UnderlineBeg Event::UnderlineBeg
} }
Object::Strike { end } => { Object::Strike { end } => {
debug_assert!(end <= text.len()); debug_assert!(end <= text.len());
self.stack.push(Container::Strike { self.stack
cont_end: self.off + end - 1, .push((Container::Strike, end + self.off - 1, end + self.off));
end: self.off + end,
});
Event::StrikeBeg Event::StrikeBeg
} }
Object::Italic { end } => { Object::Italic { end } => {
debug_assert!(end <= text.len()); debug_assert!(end <= text.len());
self.stack.push(Container::Italic { self.stack
cont_end: self.off + end - 1, .push((Container::Italic, end + self.off - 1, end + self.off));
end: self.off + end,
});
Event::ItalicBeg Event::ItalicBeg
} }
Object::Bold { end } => { Object::Bold { end } => {
debug_assert!(end <= text.len()); debug_assert!(end <= text.len());
self.stack.push(Container::Bold { self.stack
cont_end: self.off + end - 1, .push((Container::Bold, end + self.off - 1, end + self.off));
end: self.off + end,
});
Event::BoldBeg Event::BoldBeg
} }
Object::Code(c) => Event::Code(c), Object::Code(c) => Event::Code(c),
@ -418,31 +358,30 @@ impl<'a> Parser<'a> {
fn next_list_item(&mut self, ident: usize, end: usize) -> Event<'a> { fn next_list_item(&mut self, ident: usize, end: usize) -> Event<'a> {
let (bullet, off, cont_end, end, has_more) = list::parse(&self.text[self.off..end], ident); let (bullet, off, cont_end, end, has_more) = list::parse(&self.text[self.off..end], ident);
self.stack.push(Container::ListItem { self.stack
cont_end: self.off + cont_end, .push((Container::ListItem, cont_end + self.off, end + self.off));
end: self.off + end,
});
self.off += off; self.off += off;
self.has_more_item = has_more; self.list_more_item = has_more;
Event::ListItemBeg { bullet } Event::ListItemBeg { bullet }
} }
#[inline] #[inline]
fn end(&mut self) -> Event<'a> { fn end(&mut self) -> Event<'a> {
match self.stack.pop().unwrap() { let (container, _, _) = self.stack.pop().unwrap();
Container::Bold { .. } => Event::BoldEnd, match container {
Container::CtrBlock { .. } => Event::CtrBlockEnd, Container::Bold => Event::BoldEnd,
Container::DynBlock { .. } => Event::DynBlockEnd, Container::CtrBlock => Event::CtrBlockEnd,
Container::Headline { .. } => Event::HeadlineEnd, Container::DynBlock => Event::DynBlockEnd,
Container::Italic { .. } => Event::ItalicEnd, Container::Headline(_) => Event::HeadlineEnd,
Container::List { ordered, .. } => Event::ListEnd { ordered }, Container::Italic => Event::ItalicEnd,
Container::ListItem { .. } => Event::ListItemEnd, Container::List(_, ordered) => Event::ListEnd { ordered },
Container::Paragraph { .. } => Event::ParagraphEnd, Container::ListItem => Event::ListItemEnd,
Container::QteBlock { .. } => Event::QteBlockEnd, Container::Paragraph => Event::ParagraphEnd,
Container::Section { .. } => Event::SectionEnd, Container::QteBlock => Event::QteBlockEnd,
Container::SplBlock { .. } => Event::SplBlockEnd, Container::Section => Event::SectionEnd,
Container::Strike { .. } => Event::StrikeEnd, Container::SplBlock => Event::SplBlockEnd,
Container::Underline { .. } => Event::UnderlineEnd, Container::Strike => Event::StrikeEnd,
Container::Underline => Event::UnderlineEnd,
} }
} }
} }
@ -454,60 +393,40 @@ impl<'a> Iterator for Parser<'a> {
self.stack self.stack
.last() .last()
.cloned() .cloned()
.map(|x| match x { .map(|(container, cont_end, end)| {
Container::Headline { beg, end } => { if self.off >= cont_end {
debug_assert!(self.off >= beg);
debug_assert!(self.off <= end);
if self.off >= end {
self.end()
} else if self.off == beg {
self.next_sec_or_hdl()
} else {
self.next_hdl()
}
}
Container::DynBlock { cont_end, end, .. }
| Container::CtrBlock { cont_end, end, .. }
| Container::QteBlock { cont_end, end, .. }
| Container::SplBlock { cont_end, end, .. }
| Container::ListItem { cont_end, end } => {
debug_assert!(self.off <= cont_end); debug_assert!(self.off <= cont_end);
debug_assert!(self.off <= end); debug_assert!(self.off <= end);
if self.off >= cont_end { self.off = end;
self.off = end; self.end()
self.end() } else {
} else { match container {
self.next_ele(cont_end) Container::Headline(beg) => {
} debug_assert!(self.off >= beg);
} if self.off == beg {
Container::List { ident, end, .. } => { self.next_section_or_headline()
debug_assert!(self.off <= end); } else {
if self.has_more_item { self.next_headline()
self.next_list_item(ident, end) }
} else { }
self.end() Container::DynBlock
} | Container::CtrBlock
} | Container::QteBlock
Container::Section { end } => { | Container::SplBlock
debug_assert!(self.off <= end); | Container::ListItem
if self.off >= end { | Container::Section => self.next_ele(end),
self.end() Container::List(ident, _) => {
} else { if self.list_more_item {
self.next_ele(end) self.next_list_item(ident, end)
} } else {
} self.end()
Container::Paragraph { cont_end, end } }
| Container::Bold { cont_end, end } }
| Container::Underline { cont_end, end } Container::Paragraph
| Container::Italic { cont_end, end } | Container::Bold
| Container::Strike { cont_end, end } => { | Container::Underline
debug_assert!(self.off <= cont_end); | Container::Italic
debug_assert!(self.off <= end); | Container::Strike => self.next_obj(cont_end),
if self.off >= cont_end {
self.off = end;
self.end()
} else {
self.next_obj(cont_end)
} }
} }
}) })
@ -515,7 +434,7 @@ impl<'a> Iterator for Parser<'a> {
if self.off >= self.text.len() { if self.off >= self.text.len() {
None None
} else { } else {
Some(self.next_sec_or_hdl()) Some(self.next_section_or_headline())
} }
}) })
} }