From 443a27af15ea9fb6898f6ae2d83616ccd6bc4ff8 Mon Sep 17 00:00:00 2001 From: Alextopher Date: Wed, 3 Aug 2022 10:48:09 -0400 Subject: [PATCH 1/2] Span::lines_span() and refactor span::Lines --- pest/src/lib.rs | 2 +- pest/src/span.rs | 89 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/pest/src/lib.rs b/pest/src/lib.rs index 003135b1..d4a12e3d 100644 --- a/pest/src/lib.rs +++ b/pest/src/lib.rs @@ -77,7 +77,7 @@ extern crate serde_json; pub use crate::parser::Parser; pub use crate::parser_state::{state, Atomicity, Lookahead, MatchDir, ParseResult, ParserState}; pub use crate::position::Position; -pub use crate::span::{Lines, Span}; +pub use crate::span::{Lines, LinesSpan, Span}; pub use crate::token::Token; use core::fmt::Debug; use core::hash::Hash; diff --git a/pest/src/span.rs b/pest/src/span.rs index 9f375fa3..7f94b508 100644 --- a/pest/src/span.rs +++ b/pest/src/span.rs @@ -180,7 +180,7 @@ impl<'i> Span<'i> { &self.input[self.start..self.end] } - /// Iterates over all lines (partially) covered by this span. + /// Iterates over all lines (partially) covered by this span. Yeilding a `&str` for each line. /// /// # Examples /// @@ -200,6 +200,30 @@ impl<'i> Span<'i> { #[inline] pub fn lines(&self) -> Lines { Lines { + inner: self.lines_span(), + } + } + + /// Iterates over all lines (partially) covered by this span. Yeilding a `Span` for each line. + /// + /// # Examples + /// + /// ``` + /// # use pest; + /// # use pest::Span; + /// # #[allow(non_camel_case_types)] + /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + /// enum Rule {} + /// + /// let input = "a\nb\nc"; + /// let mut state: Box> = pest::ParserState::new(input).skip(2).unwrap(); + /// let start_pos = state.position().clone(); + /// state = state.match_string("b\nc").unwrap(); + /// let span = start_pos.span(&state.position().clone()); + /// assert_eq!(span.lines_span().collect::>(), vec![Span::new(input, 2, 4).unwrap(), Span::new(input, 4, 5).unwrap()]); + /// ``` + pub fn lines_span(&self) -> LinesSpan { + LinesSpan { span: self, pos: self.start, } @@ -232,19 +256,19 @@ impl<'i> Hash for Span<'i> { } } -/// Line iterator for Spans, created by [`Span::lines()`]. +/// Line iterator for Spans, created by [`Span::lines_span()`]. /// -/// Iterates all lines that are at least partially covered by the span. +/// Iterates all lines that are at least _partially_ covered by the span. Yielding a `Span` for each. /// -/// [`Span::lines()`]: struct.Span.html#method.lines -pub struct Lines<'i> { +/// [`Span::lines_span()`]: struct.Span.html#method.lines_span +pub struct LinesSpan<'i> { span: &'i Span<'i>, pos: usize, } -impl<'i> Iterator for Lines<'i> { - type Item = &'i str; - fn next(&mut self) -> Option<&'i str> { +impl<'i> Iterator for LinesSpan<'i> { + type Item = Span<'i>; + fn next(&mut self) -> Option { if self.pos > self.span.end { return None; } @@ -252,9 +276,27 @@ impl<'i> Iterator for Lines<'i> { if pos.at_end() { return None; } - let line = pos.line_of(); + + let line_start = pos.find_line_start(); self.pos = pos.find_line_end(); - Some(line) + + Span::new(self.span.input, line_start, self.pos) + } +} + +/// Line iterator for Spans, created by [`Span::lines()`]. +/// +/// Iterates all lines that are at least _partially_ covered by the span. Yielding a `&str` for each. +/// +/// [`Span::lines()`]: struct.Span.html#method.lines +pub struct Lines<'i> { + inner: LinesSpan<'i>, +} + +impl<'i> Iterator for Lines<'i> { + type Item = &'i str; + fn next(&mut self) -> Option { + self.inner.next().map(|span| span.as_str()) } } @@ -292,10 +334,12 @@ mod tests { let input = "abc\ndef\nghi"; let span = Span::new(input, 1, 7).unwrap(); let lines: Vec<_> = span.lines().collect(); - //println!("{:?}", lines); + let lines_span: Vec<_> = span.lines_span().map(|span| span.as_str()).collect(); + assert_eq!(lines.len(), 2); assert_eq!(lines[0], "abc\n".to_owned()); assert_eq!(lines[1], "def\n".to_owned()); + assert_eq!(lines, lines_span) // Verify parity with lines_span() } #[test] @@ -305,9 +349,30 @@ mod tests { assert!(span.end_pos().at_end()); assert_eq!(span.end(), 11); let lines: Vec<_> = span.lines().collect(); - //println!("{:?}", lines); + let lines_span: Vec<_> = span.lines_span().map(|span| span.as_str()).collect(); + assert_eq!(lines.len(), 2); assert_eq!(lines[0], "def\n".to_owned()); assert_eq!(lines[1], "ghi".to_owned()); + assert_eq!(lines, lines_span) // Verify parity with lines_span() + } + + #[test] + fn lines_span() { + let input = "abc\ndef\nghi"; + let span = Span::new(input, 1, 7).unwrap(); + let lines_span: Vec<_> = span.lines_span().collect(); + let lines: Vec<_> = span.lines().collect(); + + assert_eq!(lines_span.len(), 2); + assert_eq!(lines_span[0], Span::new(input, 0, 4).unwrap()); + assert_eq!(lines_span[1], Span::new(input, 4, 8).unwrap()); + assert_eq!( + lines_span + .iter() + .map(|span| span.as_str()) + .collect::>(), + lines + ); } } From 6b01e3e22f9ca1cd7e746eccc0c11cab33c1e444 Mon Sep 17 00:00:00 2001 From: Tomas Tauber <2410580+tomtau@users.noreply.github.com> Date: Thu, 4 Aug 2022 09:09:01 +0800 Subject: [PATCH 2/2] nit: typo fixes --- pest/src/span.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pest/src/span.rs b/pest/src/span.rs index 7f94b508..d1c6610b 100644 --- a/pest/src/span.rs +++ b/pest/src/span.rs @@ -180,7 +180,7 @@ impl<'i> Span<'i> { &self.input[self.start..self.end] } - /// Iterates over all lines (partially) covered by this span. Yeilding a `&str` for each line. + /// Iterates over all lines (partially) covered by this span. Yielding a `&str` for each line. /// /// # Examples /// @@ -204,7 +204,7 @@ impl<'i> Span<'i> { } } - /// Iterates over all lines (partially) covered by this span. Yeilding a `Span` for each line. + /// Iterates over all lines (partially) covered by this span. Yielding a `Span` for each line. /// /// # Examples ///