summaryrefslogtreecommitdiff
path: root/src/parse
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-06-13 23:16:40 +0200
committerLaurenz <laurmaedje@gmail.com>2022-06-14 13:53:02 +0200
commitc81e2a5f56eb262663f292578c683fba7f18251f (patch)
tree6c045a8dcbec5e75e01a15f970ef8cee6ff042d0 /src/parse
parent891af17260a6750a74a102388a05e59cf1ffc3c1 (diff)
Many fixes
Diffstat (limited to 'src/parse')
-rw-r--r--src/parse/incremental.rs51
-rw-r--r--src/parse/mod.rs54
-rw-r--r--src/parse/parser.rs34
-rw-r--r--src/parse/resolve.rs4
-rw-r--r--src/parse/tokens.rs14
5 files changed, 84 insertions, 73 deletions
diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs
index c6b81aea..d3d6b07a 100644
--- a/src/parse/incremental.rs
+++ b/src/parse/incremental.rs
@@ -54,7 +54,7 @@ impl Reparser<'_> {
outermost: bool,
safe_to_replace: bool,
) -> Option<Range<usize>> {
- let is_markup = matches!(node.kind(), NodeKind::Markup(_));
+ let is_markup = matches!(node.kind(), NodeKind::Markup { .. });
let original_count = node.children().len();
let original_offset = offset;
@@ -96,9 +96,8 @@ impl Reparser<'_> {
} else {
// Update compulsary state of `ahead_nontrivia`.
if let Some(ahead_nontrivia) = ahead.as_mut() {
- match child.kind() {
- NodeKind::Space(n) if n > &0 => ahead_nontrivia.newline(),
- _ => {}
+ if let NodeKind::Space { newlines: (1 ..) } = child.kind() {
+ ahead_nontrivia.newline();
}
}
@@ -156,7 +155,6 @@ impl Reparser<'_> {
// Do not allow replacement of elements inside of constructs whose
// opening and closing brackets look the same.
let safe_inside = node.kind().is_bounded();
-
let child = &mut node.children_mut()[pos.idx];
let prev_len = child.len();
let prev_descendants = child.descendants();
@@ -200,8 +198,8 @@ impl Reparser<'_> {
// Make sure this is a markup node and that we may replace. If so, save
// the current indent.
- let indent = match node.kind() {
- NodeKind::Markup(n) if safe_to_replace => *n,
+ let min_indent = match node.kind() {
+ NodeKind::Markup { min_indent } if safe_to_replace => *min_indent,
_ => return None,
};
@@ -220,7 +218,7 @@ impl Reparser<'_> {
self.replace(
node,
- ReparseMode::MarkupElements(at_start, indent),
+ ReparseMode::MarkupElements { at_start, min_indent },
start.idx .. end.idx + 1,
superseded_span,
outermost,
@@ -261,15 +259,17 @@ impl Reparser<'_> {
&self.src[newborn_span.start ..],
newborn_span.len(),
),
- ReparseMode::MarkupElements(at_start, indent) => reparse_markup_elements(
- &prefix,
- &self.src[newborn_span.start ..],
- newborn_span.len(),
- differential,
- &node.children().as_slice()[superseded_start ..],
- at_start,
- indent,
- ),
+ ReparseMode::MarkupElements { at_start, min_indent } => {
+ reparse_markup_elements(
+ &prefix,
+ &self.src[newborn_span.start ..],
+ newborn_span.len(),
+ differential,
+ &node.children().as_slice()[superseded_start ..],
+ at_start,
+ min_indent,
+ )
+ }
}?;
// Do not accept unclosed nodes if the old node wasn't at the right edge
@@ -294,12 +294,12 @@ struct NodePos {
offset: usize,
}
-/// Encodes the state machine of the search for the node which is pending for
+/// Encodes the state machine of the search for the nodes are pending for
/// replacement.
#[derive(Clone, Copy, Debug, PartialEq)]
enum SearchState {
/// Neither an end nor a start have been found as of now.
- /// The last non-whitespace child is continually saved.
+ /// The latest non-trivia child is continually saved.
NoneFound,
/// The search has concluded by finding a node that fully contains the
/// modifications.
@@ -332,15 +332,18 @@ impl SearchState {
}
}
-/// An ahead element with an index and whether it is `at_start`.
+/// An ahead node with an index and whether it is `at_start`.
#[derive(Clone, Copy, Debug, PartialEq)]
struct Ahead {
+ /// The position of the node.
pos: NodePos,
+ /// The `at_start` before this node.
at_start: bool,
+ /// The kind of ahead node.
kind: AheadKind,
}
-/// The kind of ahead element.
+/// The kind of ahead node.
#[derive(Clone, Copy, Debug, PartialEq)]
enum AheadKind {
/// A normal non-trivia child has been found.
@@ -382,9 +385,9 @@ enum ReparseMode {
Code,
/// Reparse a content block, including its square brackets.
Content,
- /// Reparse elements of the markup. The variant carries whether the node is
- /// `at_start` and the minimum indent of the containing markup node.
- MarkupElements(bool, usize),
+ /// Reparse elements of the markup. Also specified the initial `at_start`
+ /// state for the reparse and the minimum indent of the reparsed nodes.
+ MarkupElements { at_start: bool, min_indent: usize },
}
#[cfg(test)]
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 98f25cab..d266ce95 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -77,7 +77,7 @@ fn reparse_content_block(
Some((vec![first], terminated, 1))
}
-/// Reparse some markup elements without the topmost node.
+/// Reparse a sequence markup elements without the topmost node.
///
/// Returns `Some` if all of the input was consumed.
fn reparse_markup_elements(
@@ -87,7 +87,7 @@ fn reparse_markup_elements(
differential: isize,
reference: &[SyntaxNode],
mut at_start: bool,
- column: usize,
+ min_indent: usize,
) -> Option<(Vec<SyntaxNode>, bool, usize)> {
let mut p = Parser::with_prefix(prefix, src, TokenMode::Markup);
@@ -98,8 +98,8 @@ fn reparse_markup_elements(
let mut stopped = false;
'outer: while !p.eof() {
- if let Some(NodeKind::Space(1 ..)) = p.peek() {
- if p.column(p.current_end()) < column {
+ if let Some(NodeKind::Space { newlines: (1 ..) }) = p.peek() {
+ if p.column(p.current_end()) < min_indent {
return None;
}
}
@@ -155,7 +155,7 @@ fn reparse_markup_elements(
/// If `at_start` is true, things like headings that may only appear at the
/// beginning of a line or content block are initially allowed.
fn markup(p: &mut Parser, mut at_start: bool) {
- p.perform(NodeKind::Markup(0), |p| {
+ p.perform(NodeKind::Markup { min_indent: 0 }, |p| {
while !p.eof() {
markup_node(p, &mut at_start);
}
@@ -168,18 +168,18 @@ fn markup_line(p: &mut Parser) {
}
/// Parse markup that stays right of the given `column`.
-fn markup_indented(p: &mut Parser, column: usize) {
+fn markup_indented(p: &mut Parser, min_indent: usize) {
p.eat_while(|t| match t {
- NodeKind::Space(n) => *n == 0,
+ NodeKind::Space { newlines } => *newlines == 0,
NodeKind::LineComment | NodeKind::BlockComment => true,
_ => false,
});
let mut at_start = false;
- p.perform(NodeKind::Markup(column), |p| {
+ p.perform(NodeKind::Markup { min_indent }, |p| {
while !p.eof() {
- if let Some(NodeKind::Space(1 ..)) = p.peek() {
- if p.column(p.current_end()) < column {
+ if let Some(NodeKind::Space { newlines: (1 ..) }) = p.peek() {
+ if p.column(p.current_end()) < min_indent {
break;
}
}
@@ -198,7 +198,7 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) {
match token {
// Whitespace.
- NodeKind::Space(newlines) => {
+ NodeKind::Space { newlines } => {
*at_start |= *newlines > 0;
p.eat();
return;
@@ -284,7 +284,7 @@ fn heading(p: &mut Parser, at_start: bool) {
while p.eat_if(NodeKind::Eq) {}
if at_start && p.peek().map_or(true, |kind| kind.is_space()) {
- p.eat_while(|kind| kind == &NodeKind::Space(0));
+ p.eat_while(|kind| *kind == NodeKind::Space { newlines: 0 });
markup_line(p);
marker.end(p, NodeKind::Heading);
} else {
@@ -299,9 +299,9 @@ fn list_node(p: &mut Parser, at_start: bool) {
let text: EcoString = p.peek_src().into();
p.assert(NodeKind::Minus);
- let column = p.column(p.prev_end());
- if at_start && p.eat_if(NodeKind::Space(0)) && !p.eof() {
- markup_indented(p, column);
+ let min_indent = p.column(p.prev_end());
+ if at_start && p.eat_if(NodeKind::Space { newlines: 0 }) && !p.eof() {
+ markup_indented(p, min_indent);
marker.end(p, NodeKind::List);
} else {
marker.convert(p, NodeKind::Text(text));
@@ -314,16 +314,16 @@ fn enum_node(p: &mut Parser, at_start: bool) {
let text: EcoString = p.peek_src().into();
p.eat();
- let column = p.column(p.prev_end());
- if at_start && p.eat_if(NodeKind::Space(0)) && !p.eof() {
- markup_indented(p, column);
+ let min_indent = p.column(p.prev_end());
+ if at_start && p.eat_if(NodeKind::Space { newlines: 0 }) && !p.eof() {
+ markup_indented(p, min_indent);
marker.end(p, NodeKind::Enum);
} else {
marker.convert(p, NodeKind::Text(text));
}
}
-/// Parse an expression within markup mode.
+/// Parse an expression within a markup mode.
fn markup_expr(p: &mut Parser) {
// Does the expression need termination or can content follow directly?
let stmt = matches!(
@@ -556,10 +556,10 @@ fn parenthesized(p: &mut Parser, atomic: bool) -> ParseResult {
enum CollectionKind {
/// The collection is only one item and has no comma.
Group,
- /// The collection starts with a positional and has more items or a trailing
- /// comma.
+ /// The collection starts with a positional item and has multiple items or a
+ /// trailing comma.
Positional,
- /// The collection starts with a named item.
+ /// The collection starts with a colon or named item.
Named,
}
@@ -672,7 +672,7 @@ fn array(p: &mut Parser, marker: Marker) {
}
/// Convert a collection into a dictionary, producing errors for anything other
-/// than named pairs.
+/// than named and keyed pairs.
fn dict(p: &mut Parser, marker: Marker) {
let mut used = HashSet::new();
marker.filter_children(p, |x| match x.kind() {
@@ -731,11 +731,11 @@ fn code(p: &mut Parser) {
p.end_group();
// Forcefully skip over newlines since the group's contents can't.
- p.eat_while(|t| matches!(t, NodeKind::Space(_)));
+ p.eat_while(NodeKind::is_space);
}
}
-// Parse a content block: `[...]`.
+/// Parse a content block: `[...]`.
fn content_block(p: &mut Parser) {
p.perform(NodeKind::ContentBlock, |p| {
p.start_group(Group::Bracket);
@@ -857,7 +857,7 @@ fn wrap_expr(p: &mut Parser) -> ParseResult {
})
}
-/// Parse an if expresion.
+/// Parse an if-else expresion.
fn if_expr(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::IfExpr, |p| {
p.assert(NodeKind::If);
@@ -886,7 +886,7 @@ fn while_expr(p: &mut Parser) -> ParseResult {
})
}
-/// Parse a for expression.
+/// Parse a for-in expression.
fn for_expr(p: &mut Parser) -> ParseResult {
p.perform(NodeKind::ForExpr, |p| {
p.assert(NodeKind::For);
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index f4b02a9c..685f1e69 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -24,7 +24,7 @@ pub struct Parser<'s> {
children: Vec<SyntaxNode>,
/// Whether the last group was not correctly terminated.
unterminated_group: bool,
- /// Whether a group terminator was found, that did not close a group.
+ /// Whether a group terminator was found that did not close a group.
stray_terminator: bool,
}
@@ -58,9 +58,10 @@ impl<'s> Parser<'s> {
self.children
}
- /// End the parsing process and return the parsed children and whether the
- /// last token was terminated if all groups were terminated correctly or
- /// `None` otherwise.
+ /// End the parsing process and return
+ /// - the parsed children and whether the last token was terminated, if all
+ /// groups were terminated correctly, or
+ /// - `None` otherwise.
pub fn consume(self) -> Option<(Vec<SyntaxNode>, bool)> {
self.terminated().then(|| (self.children, self.tokens.terminated()))
}
@@ -131,7 +132,7 @@ impl<'s> Parser<'s> {
self.repeek();
}
- /// Eat if the current token it is the given one.
+ /// Consume the current token if it is the given one.
pub fn eat_if(&mut self, kind: NodeKind) -> bool {
let at = self.at(kind);
if at {
@@ -150,7 +151,8 @@ impl<'s> Parser<'s> {
}
}
- /// Eat if the current token is the given one and produce an error if not.
+ /// Consume the current token if it is the given one and produce an error if
+ /// not.
pub fn expect(&mut self, kind: NodeKind) -> ParseResult {
let at = self.peek() == Some(&kind);
if at {
@@ -162,7 +164,7 @@ impl<'s> Parser<'s> {
}
}
- /// Eat, debug-asserting that the token is the given one.
+ /// Consume the current token, debug-asserting that it is the given one.
#[track_caller]
pub fn assert(&mut self, kind: NodeKind) {
debug_assert_eq!(self.peek(), Some(&kind));
@@ -179,8 +181,8 @@ impl<'s> Parser<'s> {
if self.eof { None } else { self.current.as_ref() }
}
- /// Peek at the current token, if it follows immediately after the last one
- /// without any trivia in between.
+ /// Peek at the current token, but only if it follows immediately after the
+ /// last one without any trivia in between.
pub fn peek_direct(&self) -> Option<&NodeKind> {
if self.prev_end() == self.current_start() {
self.peek()
@@ -267,9 +269,9 @@ impl<'s> Parser<'s> {
Group::Imports => None,
} {
if self.current.as_ref() == Some(&end) {
- // If another group closes after a group with the missing terminator,
- // its scope of influence ends here and no longer taints the rest of the
- // reparse.
+ // If another group closes after a group with the missing
+ // terminator, its scope of influence ends here and no longer
+ // taints the rest of the reparse.
self.unterminated_group = false;
// Bump the delimeter and return. No need to rescan in this
@@ -330,7 +332,7 @@ impl<'s> Parser<'s> {
Some(NodeKind::Underscore) => self.inside(Group::Emph),
Some(NodeKind::Semicolon) => self.inside(Group::Expr),
Some(NodeKind::From) => self.inside(Group::Imports),
- Some(NodeKind::Space(n)) => self.space_ends_group(*n),
+ Some(NodeKind::Space { newlines }) => self.space_ends_group(*newlines),
Some(_) => false,
None => true,
};
@@ -339,7 +341,7 @@ impl<'s> Parser<'s> {
/// Returns whether the given type can be skipped over.
fn is_trivia(&self, token: &NodeKind) -> bool {
match token {
- NodeKind::Space(n) => !self.space_ends_group(*n),
+ NodeKind::Space { newlines } => !self.space_ends_group(*newlines),
NodeKind::LineComment => true,
NodeKind::BlockComment => true,
_ => false,
@@ -491,8 +493,8 @@ impl Marker {
/// A logical group of tokens, e.g. `[...]`.
#[derive(Debug)]
struct GroupEntry {
- /// The kind of group this is. This decides which tokens will end the group.
- /// For example, a [`Group::Paren`] will be ended by
+ /// The kind of group this is. This decides which token(s) will end the
+ /// group. For example, a [`Group::Paren`] will be ended by
/// [`Token::RightParen`].
pub kind: Group,
/// The mode the parser was in _before_ the group started (to which we go
diff --git a/src/parse/resolve.rs b/src/parse/resolve.rs
index dd9ed4f4..6fab9f21 100644
--- a/src/parse/resolve.rs
+++ b/src/parse/resolve.rs
@@ -47,7 +47,7 @@ pub fn resolve_hex(sequence: &str) -> Option<char> {
u32::from_str_radix(sequence, 16).ok().and_then(std::char::from_u32)
}
-/// Resolve the language tag and trims the raw text.
+/// Resolve the language tag and trim the raw text.
pub fn resolve_raw(column: usize, backticks: usize, text: &str) -> RawNode {
if backticks > 1 {
let (tag, inner) = split_at_lang_tag(text);
@@ -77,7 +77,7 @@ fn split_at_lang_tag(raw: &str) -> (&str, &str) {
/// Trim raw text and splits it into lines.
///
-/// Returns whether at least one newline was contained in `raw`.
+/// Also returns whether at least one newline was contained in `raw`.
fn trim_and_split_raw(column: usize, mut raw: &str) -> (String, bool) {
// Trims one space at the start.
raw = raw.strip_prefix(' ').unwrap_or(raw);
diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs
index ff36c6be..be107f3c 100644
--- a/src/parse/tokens.rs
+++ b/src/parse/tokens.rs
@@ -110,7 +110,9 @@ impl<'s> Iterator for Tokens<'s> {
']' => NodeKind::RightBracket,
// Whitespace.
- ' ' if self.s.done() || !self.s.at(char::is_whitespace) => NodeKind::Space(0),
+ ' ' if self.s.done() || !self.s.at(char::is_whitespace) => {
+ NodeKind::Space { newlines: 0 }
+ }
c if c.is_whitespace() => self.whitespace(),
// Comments with special case for URLs.
@@ -260,7 +262,7 @@ impl<'s> Tokens<'s> {
}
}
- NodeKind::Space(newlines)
+ NodeKind::Space { newlines }
}
fn backslash(&mut self) -> NodeKind {
@@ -681,8 +683,8 @@ mod tests {
use SpanPos::*;
use TokenMode::{Code, Markup};
- fn Error(pos: SpanPos, message: &str) -> NodeKind {
- NodeKind::Error(pos, message.into())
+ fn Space(newlines: usize) -> NodeKind {
+ NodeKind::Space { newlines }
}
fn Raw(text: &str, lang: Option<&str>, block: bool) -> NodeKind {
@@ -709,6 +711,10 @@ mod tests {
NodeKind::Ident(ident.into())
}
+ fn Error(pos: SpanPos, message: &str) -> NodeKind {
+ NodeKind::Error(pos, message.into())
+ }
+
fn Invalid(invalid: &str) -> NodeKind {
NodeKind::Unknown(invalid.into())
}