diff options
| author | Martin Haug <mhaug@live.de> | 2022-01-03 23:18:21 +0100 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2022-01-04 00:21:33 +0100 |
| commit | c994cfa7d814e3909682b19322867ed5c676c453 (patch) | |
| tree | 03349230f74786c7128876889c07a31a4932f108 /src/parse/mod.rs | |
| parent | 98c96ba1cb8a46e327de313118e4ce1a84795ae9 (diff) | |
Code Review: Your parsers were so preoccupied with whether they could
Diffstat (limited to 'src/parse/mod.rs')
| -rw-r--r-- | src/parse/mod.rs | 147 |
1 files changed, 87 insertions, 60 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index f4826730..a9752645 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -29,72 +29,102 @@ pub fn parse(src: &str) -> Rc<GreenNode> { } /// Parse an atomic primary. Returns `Some` if all of the input was consumed. -pub fn parse_atomic(src: &str, _: bool, _: usize) -> Option<(Vec<Green>, bool)> { - let mut p = Parser::new(src, TokenMode::Code); +pub fn parse_atomic( + prefix: &str, + src: &str, + _: bool, + _: usize, +) -> Option<(Vec<Green>, bool)> { + let mut p = Parser::with_prefix(prefix, src, TokenMode::Code); primary(&mut p, true).ok()?; - p.eject_partial() + p.consume_unterminated() } /// Parse an atomic primary. Returns `Some` if all of the input was consumed. -pub fn parse_atomic_markup(src: &str, _: bool, _: usize) -> Option<(Vec<Green>, bool)> { - let mut p = Parser::new(src, TokenMode::Markup); +pub fn parse_atomic_markup( + prefix: &str, + src: &str, + _: bool, + _: usize, +) -> Option<(Vec<Green>, bool)> { + let mut p = Parser::with_prefix(prefix, src, TokenMode::Markup); markup_expr(&mut p); - p.eject_partial() + p.consume_unterminated() } /// Parse some markup. Returns `Some` if all of the input was consumed. -pub fn parse_markup(src: &str, _: bool, column: usize) -> Option<(Vec<Green>, bool)> { - let mut p = Parser::new(src, TokenMode::Markup); - if column == 0 { +pub fn parse_markup( + prefix: &str, + src: &str, + _: bool, + min_column: usize, +) -> Option<(Vec<Green>, bool)> { + let mut p = Parser::with_prefix(prefix, src, TokenMode::Markup); + if min_column == 0 { markup(&mut p); } else { - markup_indented(&mut p, column); + markup_indented(&mut p, min_column); } - p.eject() + p.consume() } /// Parse some markup without the topmost node. Returns `Some` if all of the /// input was consumed. pub fn parse_markup_elements( + prefix: &str, src: &str, mut at_start: bool, - column: usize, + _: usize, ) -> Option<(Vec<Green>, bool)> { - let mut p = Parser::new(src, TokenMode::Markup); - p.offset(column); + let mut p = Parser::with_prefix(prefix, src, TokenMode::Markup); while !p.eof() { markup_node(&mut p, &mut at_start); } - p.eject() + p.consume() } /// Parse a template literal. Returns `Some` if all of the input was consumed. -pub fn parse_template(source: &str, _: bool, _: usize) -> Option<(Vec<Green>, bool)> { - let mut p = Parser::new(source, TokenMode::Code); +pub fn parse_template( + prefix: &str, + src: &str, + _: bool, + _: usize, +) -> Option<(Vec<Green>, bool)> { + let mut p = Parser::with_prefix(prefix, src, TokenMode::Code); if !p.at(&NodeKind::LeftBracket) { return None; } template(&mut p); - p.eject() + p.consume() } /// Parse a code block. Returns `Some` if all of the input was consumed. -pub fn parse_block(source: &str, _: bool, _: usize) -> Option<(Vec<Green>, bool)> { - let mut p = Parser::new(source, TokenMode::Code); +pub fn parse_block( + prefix: &str, + src: &str, + _: bool, + _: usize, +) -> Option<(Vec<Green>, bool)> { + let mut p = Parser::with_prefix(prefix, src, TokenMode::Code); if !p.at(&NodeKind::LeftBrace) { return None; } block(&mut p); - p.eject() + p.consume() } /// Parse a comment. Returns `Some` if all of the input was consumed. -pub fn parse_comment(source: &str, _: bool, _: usize) -> Option<(Vec<Green>, bool)> { - let mut p = Parser::new(source, TokenMode::Code); +pub fn parse_comment( + prefix: &str, + src: &str, + _: bool, + _: usize, +) -> Option<(Vec<Green>, bool)> { + let mut p = Parser::with_prefix(prefix, src, TokenMode::Code); comment(&mut p).ok()?; - p.eject() + p.consume() } /// Parse markup. @@ -111,7 +141,7 @@ fn markup_indented(p: &mut Parser, column: usize) { }); markup_while(p, false, column, &mut |p| match p.peek() { - Some(NodeKind::Space(n)) if *n >= 1 => p.clean_column(p.current_end()) >= column, + Some(NodeKind::Space(n)) if *n >= 1 => p.column(p.current_end()) >= column, _ => true, }) } @@ -170,14 +200,9 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) { p.eat(); } - NodeKind::Eq if *at_start => heading(p), - NodeKind::Minus if *at_start => list_node(p), - NodeKind::EnumNumbering(_) if *at_start => enum_node(p), - - // Line-based markup that is not currently at the start of the line. - NodeKind::Eq | NodeKind::Minus | NodeKind::EnumNumbering(_) => { - p.convert(NodeKind::TextInLine(p.peek_src().into())) - } + NodeKind::Eq => heading(p, *at_start), + NodeKind::Minus => list_node(p, *at_start), + NodeKind::EnumNumbering(_) => enum_node(p, *at_start), // Hashtag + keyword / identifier. NodeKind::Ident(_) @@ -201,42 +226,49 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) { } /// Parse a heading. -fn heading(p: &mut Parser) { - p.perform(NodeKind::Heading, |p| { - p.eat_assert(&NodeKind::Eq); - while p.eat_if(&NodeKind::Eq) {} +fn heading(p: &mut Parser, at_start: bool) { + let marker = p.marker(); + let current_start = p.current_start(); + p.eat_assert(&NodeKind::Eq); + while p.eat_if(&NodeKind::Eq) {} + + if at_start && p.peek().map_or(true, |kind| kind.is_whitespace()) { let column = p.column(p.prev_end()); markup_indented(p, column); - }); + marker.end(p, NodeKind::Heading); + } else { + let text = p.get(current_start .. p.prev_end()).into(); + marker.convert(p, NodeKind::TextInLine(text)); + } } /// Parse a single list item. -fn list_node(p: &mut Parser) { +fn list_node(p: &mut Parser, at_start: bool) { let marker = p.marker(); - let src: EcoString = p.peek_src().into(); + let text: EcoString = p.peek_src().into(); p.eat_assert(&NodeKind::Minus); - if p.peek().map_or(true, |kind| kind.is_whitespace()) { + if at_start && p.peek().map_or(true, |kind| kind.is_whitespace()) { let column = p.column(p.prev_end()); markup_indented(p, column); marker.end(p, NodeKind::List); } else { - marker.convert(p, NodeKind::TextInLine(src)); + marker.convert(p, NodeKind::TextInLine(text)); } } /// Parse a single enum item. -fn enum_node(p: &mut Parser) { +fn enum_node(p: &mut Parser, at_start: bool) { let marker = p.marker(); - let src: EcoString = p.peek_src().into(); + let text: EcoString = p.peek_src().into(); p.eat(); - if p.peek().map_or(true, |kind| kind.is_whitespace()) { + if at_start && p.peek().map_or(true, |kind| kind.is_whitespace()) { let column = p.column(p.prev_end()); markup_indented(p, column); marker.end(p, NodeKind::Enum); } else { - marker.convert(p, NodeKind::TextInLine(src)); + marker.convert(p, NodeKind::TextInLine(text)); } } @@ -582,23 +614,18 @@ fn template(p: &mut Parser) { fn block(p: &mut Parser) { p.perform(NodeKind::Block, |p| { p.start_group(Group::Brace); - expr_list(p); - p.end_group(); - }); -} + while !p.eof() { + p.start_group(Group::Stmt); + if expr(p).is_ok() && !p.eof() { + p.expected_at("semicolon or line break"); + } + p.end_group(); -/// Parse a number of code expressions. -fn expr_list(p: &mut Parser) { - while !p.eof() { - p.start_group(Group::Stmt); - if expr(p).is_ok() && !p.eof() { - p.expected_at("semicolon or line break"); + // Forcefully skip over newlines since the group's contents can't. + p.eat_while(|t| matches!(t, NodeKind::Space(_))); } p.end_group(); - - // Forcefully skip over newlines since the group's contents can't. - p.eat_while(|t| matches!(t, NodeKind::Space(_))); - } + }); } /// Parse a function call. |
