diff options
Diffstat (limited to 'src/parse')
| -rw-r--r-- | src/parse/incremental.rs | 51 | ||||
| -rw-r--r-- | src/parse/mod.rs | 54 | ||||
| -rw-r--r-- | src/parse/parser.rs | 34 | ||||
| -rw-r--r-- | src/parse/resolve.rs | 4 | ||||
| -rw-r--r-- | src/parse/tokens.rs | 14 |
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()) } |
