diff options
Diffstat (limited to 'src/parse_heirarchical.rs')
-rw-r--r-- | src/parse_heirarchical.rs | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/src/parse_heirarchical.rs b/src/parse_heirarchical.rs new file mode 100644 index 0000000..75c2bec --- /dev/null +++ b/src/parse_heirarchical.rs @@ -0,0 +1,137 @@ +use crate::*; + +macro_rules! get_subsection { + ($t:ident) => { + pub fn get_subsection(&self, name: &str) -> Option<&$t> { + for section in &self.sections { + if line_to_string(§ion.title) == name { + return Some(section); + } + } + return None; + } + }; +} + +#[derive(Default)] +pub struct Document { + pub preamble: Vec<Block>, + pub sections: Vec<TopLevelSection>, +} +impl Document { + get_subsection! {TopLevelSection} +} + +#[derive(Default)] +pub struct TopLevelSection { + pub title: Line, + pub content: Vec<Block>, + pub sections: Vec<MidLevelSection>, +} +impl TopLevelSection { + get_subsection! {MidLevelSection} +} + +#[derive(Default)] +pub struct MidLevelSection { + pub title: Line, + pub content: Vec<Block>, + pub sections: Vec<LowLevelSection>, +} +impl MidLevelSection { + get_subsection! {LowLevelSection} +} + +#[derive(Default)] +pub struct LowLevelSection { + pub title: Line, + pub content: Vec<Block>, +} + +pub fn parse_heirarchical(markdown: &str) -> Result<Document, ()> { + macro_rules! push_section { + ($from:ident => $to:ident) => { + $to.sections.push(std::mem::take(&mut $from)) + }; + } + let mut document = Document::default(); + let mut h1_buffer = TopLevelSection::default(); + let mut h2_buffer = MidLevelSection::default(); + let mut h3_buffer = LowLevelSection::default(); + let mut level = 0; + + let blocks = parse(markdown); + for block in blocks { + match (level, block) { + (0, Block::Heading1(title)) => { + h1_buffer.title = title; + level = 1; + } + (0, Block::Heading2(_)) => return Err(()), + (0, Block::Heading3(_)) => return Err(()), + (0, block) => document.preamble.push(block), + (1, Block::Heading1(title)) => { + push_section!(h1_buffer => document); + h1_buffer.title = title; + } + (1, Block::Heading2(title)) => { + h2_buffer.title = title; + level = 2; + } + (1, Block::Heading3(_)) => return Err(()), + (1, block) => h1_buffer.content.push(block), + (2, Block::Heading1(title)) => { + push_section!(h2_buffer => h1_buffer); + push_section!(h1_buffer => document); + h1_buffer.title = title; + level = 1; + } + (2, Block::Heading2(title)) => { + push_section!(h2_buffer => h1_buffer); + h2_buffer.title = title; + } + (2, Block::Heading3(title)) => { + h3_buffer.title = title; + level = 3; + } + (2, block) => h2_buffer.content.push(block), + (3, Block::Heading1(title)) => { + push_section!(h3_buffer => h2_buffer); + push_section!(h2_buffer => h1_buffer); + push_section!(h1_buffer => document); + h1_buffer.title = title; + level = 1; + } + (3, Block::Heading2(title)) => { + push_section!(h3_buffer => h2_buffer); + push_section!(h2_buffer => h1_buffer); + h2_buffer.title = title; + level = 2; + } + (3, Block::Heading3(title)) => { + push_section!(h3_buffer => h2_buffer); + h3_buffer.title = title; + } + (3, block) => h3_buffer.content.push(block), + _ => unreachable!(), + } + } + + // Push all in-progress sections + match level { + 3 => { + push_section!(h3_buffer => h2_buffer); + push_section!(h2_buffer => h1_buffer); + push_section!(h1_buffer => document); + } + 2 => { + push_section!(h2_buffer => h1_buffer); + push_section!(h1_buffer => document); + } + 1 => { + push_section!(h1_buffer => document); + } + _ => (), + } + Ok(document) +} |