refactor(parser): redesign stack structure
This commit is contained in:
parent
0b22db1f0f
commit
7273a2e84d
277
src/parser.rs
277
src/parser.rs
|
@ -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())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue