diff options
Diffstat (limited to 'src/parse/mod.rs')
| -rw-r--r-- | src/parse/mod.rs | 71 |
1 files changed, 38 insertions, 33 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 5ab5b2d8..41257668 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -25,25 +25,33 @@ pub fn parse(src: &str) -> Pass<Tree> { /// Parse a syntax tree. fn tree(p: &mut Parser) -> Tree { - tree_while(p, |_| true) + tree_while(p, true, |_| true) } /// Parse a syntax tree that stays right of the column at the start of the next /// non-whitespace token. fn tree_indented(p: &mut Parser) -> Tree { - p.skip_white(); + p.eat_while(|t| match t { + Token::Space(n) => n == 0, + Token::LineComment(_) | Token::BlockComment(_) => true, + _ => false, + }); + let column = p.column(p.next_start()); - tree_while(p, |p| match p.peek() { + tree_while(p, false, |p| match p.peek() { Some(Token::Space(n)) if n >= 1 => p.column(p.next_end()) >= column, _ => true, }) } /// Parse a syntax tree. -fn tree_while(p: &mut Parser, mut f: impl FnMut(&mut Parser) -> bool) -> Tree { - // We keep track of whether we are at the start of a block or paragraph - // to know whether things like headings are allowed. - let mut at_start = true; +fn tree_while( + p: &mut Parser, + mut at_start: bool, + mut f: impl FnMut(&mut Parser) -> bool, +) -> Tree { + // We use `at_start` to keep track of whether we are at the start of a line + // or template to know whether things like headings are allowed. let mut tree = vec![]; while !p.eof() && f(p) { if let Some(node) = node(p, &mut at_start) { @@ -85,19 +93,13 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> { Token::Star => Node::Strong(span), Token::Underscore => Node::Emph(span), Token::Raw(t) => raw(p, t), - Token::Hashtag => { - if *at_start { - return Some(heading(p)); - } else { - Node::Text(p.peek_src().into()) - } - } - Token::Hyph => { - if *at_start { - return Some(list(p)); - } else { - Node::Text(p.peek_src().into()) - } + Token::Hashtag if *at_start => return Some(heading(p)), + Token::Hyph if *at_start => return Some(list_item(p)), + Token::Numbering(number) if *at_start => return Some(enum_item(p, number)), + + // Line-based markup that is not currently at the start of the line. + Token::Hashtag | Token::Hyph | Token::Numbering(_) => { + Node::Text(p.peek_src().into()) } // Hashtag + keyword / identifier. @@ -118,19 +120,12 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> { } p.end_group(); - // Uneat spaces we might have eaten eagerly. return expr.map(Node::Expr); } - // Block. - Token::LeftBrace => { - return Some(Node::Expr(block(p, false))); - } - - // Template. - Token::LeftBracket => { - return Some(Node::Expr(template(p))); - } + // Block and template. + Token::LeftBrace => return Some(Node::Expr(block(p, false))), + Token::LeftBracket => return Some(Node::Expr(template(p))), // Comments. Token::LineComment(_) | Token::BlockComment(_) => { @@ -202,11 +197,19 @@ fn heading(p: &mut Parser) -> Node { } /// Parse a single list item. -fn list(p: &mut Parser) -> Node { +fn list_item(p: &mut Parser) -> Node { let start = p.next_start(); p.assert(Token::Hyph); let body = tree_indented(p); - Node::List(ListNode { span: p.span(start), body }) + Node::List(ListItem { span: p.span(start), body }) +} + +/// Parse a single enum item. +fn enum_item(p: &mut Parser, number: Option<usize>) -> Node { + let start = p.next_start(); + p.assert(Token::Numbering(number)); + let body = tree_indented(p); + Node::Enum(EnumItem { span: p.span(start), number, body }) } /// Parse an expression. @@ -500,7 +503,9 @@ fn block(p: &mut Parser, scoping: bool) -> Expr { } } p.end_group(); - p.skip_white(); + + // Forcefully skip over newlines since the group's contents can't. + p.eat_while(|t| matches!(t, Token::Space(_))); } let span = p.end_group(); Expr::Block(BlockExpr { span, exprs, scoping }) |
