summaryrefslogtreecommitdiff
path: root/src/parse/mod.rs
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2022-01-03 23:18:21 +0100
committerMartin Haug <mhaug@live.de>2022-01-04 00:21:33 +0100
commitc994cfa7d814e3909682b19322867ed5c676c453 (patch)
tree03349230f74786c7128876889c07a31a4932f108 /src/parse/mod.rs
parent98c96ba1cb8a46e327de313118e4ce1a84795ae9 (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.rs147
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.