FEATURE: Add a trait for tracking lines and columns in text.

This commit is contained in:
Jeremy Wall 2018-09-12 20:18:19 -05:00
parent e833730fbb
commit 2089897ab5
4 changed files with 57 additions and 1 deletions

View File

@ -759,3 +759,12 @@ macro_rules! make_fn {
}; };
} }
#[macro_export]
macro_rules! pos {
($i:expr) => {{
let _i = $i.clone();
use $crate::TextPositionTracker;
$crate::Result::Complete($i, (_i.line(), _i.column()))
}}
}

View File

@ -2,7 +2,7 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::iter::Iterator; use std::iter::Iterator;
use super::{InputIter, Offsetable, Span, SpanRange}; use super::{InputIter, Offsetable, Span, SpanRange, TextPositionTracker};
/// Implements `InputIter` for any slice of T. /// Implements `InputIter` for any slice of T.
#[derive(Debug)] #[derive(Debug)]
@ -86,6 +86,8 @@ impl<'a, T: Debug> From<&'a Vec<T>> for SliceIter<'a, T> {
pub struct StrIter<'a> { pub struct StrIter<'a> {
source: &'a str, source: &'a str,
offset: usize, offset: usize,
line: usize,
column: usize,
} }
impl<'a> StrIter<'a> { impl<'a> StrIter<'a> {
@ -94,6 +96,8 @@ impl<'a> StrIter<'a> {
StrIter { StrIter {
source: source, source: source,
offset: 0, offset: 0,
line: 1,
column: 1,
} }
} }
} }
@ -103,8 +107,15 @@ impl<'a> Iterator for StrIter<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
match self.source.as_bytes().get(self.offset) { match self.source.as_bytes().get(self.offset) {
// TODO count lines and columns.
Some(item) => { Some(item) => {
self.offset += 1; self.offset += 1;
if *item == b'\n' {
self.line += 1;
self.column = 1;
} else {
self.column += 1;
}
Some(item) Some(item)
} }
None => None, None => None,
@ -118,11 +129,23 @@ impl<'a> Offsetable for StrIter<'a> {
} }
} }
impl<'a> TextPositionTracker for StrIter<'a> {
fn line(&self) -> usize {
self.line
}
fn column(&self) -> usize {
self.column
}
}
impl<'a> Clone for StrIter<'a> { impl<'a> Clone for StrIter<'a> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
StrIter { StrIter {
source: self.source, source: self.source,
offset: self.offset, offset: self.offset,
line: self.line,
column: self.column,
} }
} }
} }

View File

@ -61,6 +61,12 @@ impl Offsetable for usize {
} }
} }
/// Trait for Inputs that can track lines and columns in a text input.
pub trait TextPositionTracker {
fn line(&self) -> usize;
fn column(&self) -> usize;
}
pub enum SpanRange { pub enum SpanRange {
Range(std::ops::Range<usize>), Range(std::ops::Range<usize>),
RangeTo(std::ops::RangeTo<usize>), RangeTo(std::ops::RangeTo<usize>),

View File

@ -462,3 +462,21 @@ fn test_ascii_ws_carriage_return() {
let result = ascii_ws(iter); let result = ascii_ws(iter);
assert!(result.is_complete()); assert!(result.is_complete());
} }
use super::TextPositionTracker;
#[test]
fn test_position_tracking_striter() {
let input_str = "\n";
let mut iter = StrIter::new(input_str);
assert_eq!(iter.line(), 1);
assert_eq!(iter.column(), 1);
iter.next();
assert_eq!(iter.line(), 2);
assert_eq!(iter.column(), 1);
let pos_result = pos!(iter);
assert!(pos_result.is_complete());
if let Result::Complete(_, (line, column)) = pos_result {
assert_eq!(line, 2);
assert_eq!(column, 1);
}
}