diff --git a/src/main.rs b/src/main.rs index 39b3980..9f327e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,11 @@ use markdown_rs::parser::Parser; use std::fs::{read_to_string, write}; +use std::time::Instant; fn main() { + let start = Instant::now(); let mut parser = Parser::new(read_to_string("test/document.md").unwrap()); let document = parser.parse(); + println!("Total duration: {:?}", start.elapsed()); write("test/document.ast", format!("{:#?}", document)).unwrap(); } diff --git a/src/parser.rs b/src/parser.rs index f56618f..eb49931 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -38,7 +38,8 @@ pub struct Parser { impl Parser { pub fn new(text: String) -> Self { - let text: Vec = text.chars().collect(); + let mut text: Vec = text.chars().collect(); + text.append(&mut vec!['\n', ' ', '\n']); // push space and newline of eof. it fixes stuff and I don't know why. let current_char = text.get(0).unwrap().clone(); Self { @@ -62,8 +63,9 @@ impl Parser { /// Returns to an index position pub fn revert_to(&mut self, index: usize) -> Result<(), ParseError> { - self.index = index - 1; - if let Some(_) = self.next_char() { + if let Some(char) = self.text.get(index) { + self.index = index; + self.current_char = char.clone(); Ok(()) } else { Err(ParseError::new(index)) @@ -132,7 +134,7 @@ impl Parser { } /// Parses a section that consists of a header and one or more blocks - pub fn parse_section(&mut self) -> Result { + fn parse_section(&mut self) -> Result { let start_index = self.index; self.seek_whitespace(); if self.current_char == '#' { @@ -171,14 +173,25 @@ impl Parser { } } + fn parse_header(&mut self) -> Result { + Ok(Header { + size: 0, + line: self.parse_inline()?, + }) + } + /// Parses a paragraph - pub fn parse_paragraph(&mut self) -> Result { + fn parse_paragraph(&mut self) -> Result { let mut paragraph = Paragraph::new(); while let Ok(token) = self.parse_inline() { paragraph.add_element(token); + let start_index = self.index; + self.seek_inline_whitespace(); if ['-', '#', '`', '|'].contains(&self.current_char) { + self.revert_to(start_index)?; break; } + self.revert_to(start_index)?; } if paragraph.elements.len() > 0 { @@ -189,7 +202,7 @@ impl Parser { } /// parses a list which consists of one or more list items - pub fn parse_list(&mut self) -> Result { + fn parse_list(&mut self) -> Result { let mut list = List::new(); let start_index = self.index; self.seek_whitespace(); @@ -205,23 +218,17 @@ impl Parser { } } - pub fn parse_table(&mut self) -> Result { - Err(ParseError::new(self.index)) - } - - pub fn parse_header(&mut self) -> Result { - Ok(Header { - size: 0, - line: self.parse_inline()?, - }) - } - /// parses a single list item defined with - - pub fn parse_list_item(&mut self) -> Result { + fn parse_list_item(&mut self) -> Result { let start_index = self.index; self.seek_inline_whitespace(); - if self.current_char != '-' { + if !['-'].contains(&self.current_char) { + let err = ParseError::new(self.index); + self.revert_to(start_index)?; + return Err(err); + } + if self.next_char() == None { let err = ParseError::new(self.index); self.revert_to(start_index)?; return Err(err); @@ -234,7 +241,71 @@ impl Parser { Ok(item) } - pub fn parse_inline(&mut self) -> Result { + fn parse_table(&mut self) -> Result { + let header = self.parse_row()?; + let start_index = self.index; + self.seek_whitespace(); + if self.current_char == '-' { + if self.next_char() != Some('|') { + let err_index = self.index; + self.revert_to(start_index)?; + return Err(ParseError::new(err_index)); + } + } + while let Some(char) = self.next_char() { + if char == '\n' { + break; + } + } + self.seek_whitespace(); + let mut table = Table::new(header); + + while let Ok(row) = self.parse_row() { + table.add_row(row); + self.seek_whitespace(); + } + + Ok(table) + } + + /// parses a table row/head + pub fn parse_row(&mut self) -> Result { + let start_index = self.index; + self.seek_inline_whitespace(); + + if self.current_char == '|' { + if self.next_char() == None { + let err_index = self.index; + self.revert_to(start_index)?; + return Err(ParseError::new(err_index)); + } + } else { + self.revert_to(start_index)?; + return Err(ParseError::new(self.index)); + } + let mut row = Row::new(); + while let Ok(element) = self.parse_inline() { + row.add_cell(Cell { text: element }); + if self.current_char == '|' { + if self.next_char() == None { + break; + } + } + if self.current_char == '\n' { + break; + } + } + + if row.cells.len() > 0 { + Ok(row) + } else { + let current_index = self.index; + self.revert_to(start_index)?; + Err(ParseError::new(current_index)) + } + } + + fn parse_inline(&mut self) -> Result { if self.index > self.text.len() { Err(ParseError::new(self.index)) } else { @@ -243,7 +314,7 @@ impl Parser { } /// Parses a line of text - pub fn parse_text(&mut self) -> Result { + fn parse_text(&mut self) -> Result { let mut text = Text::new(); while let Ok(subtext) = self.parse_subtext() { text.add_subtext(subtext); @@ -261,7 +332,7 @@ impl Parser { Ok(text) } - pub fn parse_subtext(&mut self) -> Result { + fn parse_subtext(&mut self) -> Result { match self.current_char { '*' => { parse_option!(self.next_char(), self.index); @@ -304,17 +375,17 @@ impl Parser { value: Box::new(subtext), })) } - '\n' => Err(ParseError::new(self.index)), + '\n' | '|' => Err(ParseError::new(self.index)), _ => Ok(SubText::Plain(self.parse_plain_text()?)), } } - pub fn parse_plain_text(&mut self) -> Result { + fn parse_plain_text(&mut self) -> Result { let mut current_char = self.current_char; let mut characters = String::new(); loop { match current_char { - '\n' | '*' | '_' | '~' => break, + '\n' | '*' | '_' | '~' | '|' => break, _ => characters.push(current_char), } if let Some(character) = self.next_char() { diff --git a/src/tokens.rs b/src/tokens.rs index 485f851..abccbd5 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -52,17 +52,17 @@ pub struct ListItem { #[derive(Clone, Debug)] pub struct Table { header: Row, - rows: Vec, + pub rows: Vec, } #[derive(Clone, Debug)] pub struct Row { - text: Vec, + pub(crate) cells: Vec, } #[derive(Clone, Debug)] pub struct Cell { - text: Inline, + pub(crate) text: Inline, } #[derive(Clone, Debug)] @@ -178,4 +178,27 @@ impl Text { } } +impl Table { + pub fn new(header: Row) -> Self { + Self { + header, + rows: Vec::new(), + } + } + + pub fn add_row(&mut self, row: Row) { + self.rows.push(row) + } +} + +impl Row { + pub fn new() -> Self { + Self { cells: Vec::new() } + } + + pub fn add_cell(&mut self, cell: Cell) { + self.cells.push(cell) + } +} + // TODO: Images, URIs