mirror of
https://github.com/zaphar/abortable_parser.git
synced 2025-07-21 20:29:49 -04:00
FEATURE: Add the Span trait and add a StrIter implementation.
This commit is contained in:
parent
ed908e7c13
commit
beca789911
@ -648,24 +648,25 @@ macro_rules! text_token {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! until {
|
macro_rules! until {
|
||||||
($i:expr, $term:ident!( $( $args:tt )* ) ) => {{
|
($i:expr, $term:ident!( $( $args:tt )* ) ) => {{
|
||||||
use $crate::{Result, Offsetable};
|
use $crate::{Result, Offsetable, Span, SpanRange};
|
||||||
let mut acc = Vec::new();
|
let start_offset = $i.get_offset();
|
||||||
let mut _i = $i.clone();
|
let mut _i = $i.clone();
|
||||||
let pfn = || {
|
let pfn = || {
|
||||||
loop {
|
loop {
|
||||||
match $term!(_i.clone(), $($args)*) {
|
match $term!(_i.clone(), $($args)*) {
|
||||||
Result::Complete(_, _) => return Result::Complete(_i, acc),
|
Result::Complete(_, _) => {
|
||||||
|
let range = SpanRange::Range(start_offset.._i.get_offset());
|
||||||
|
return Result::Complete(_i, $i.span(range));
|
||||||
|
},
|
||||||
Result::Abort(e) => return Result::Abort(e),
|
Result::Abort(e) => return Result::Abort(e),
|
||||||
Result::Incomplete(offset) => return Result::Incomplete(offset),
|
Result::Incomplete(offset) => return Result::Incomplete(offset),
|
||||||
Result::Fail(_) => {
|
Result::Fail(_) => {
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let item = match _i.next() {
|
if let None = _i.next() {
|
||||||
Some(it) => it,
|
return Result::Incomplete(_i.get_offset());
|
||||||
None => return Result::Incomplete(_i.get_offset()),
|
}
|
||||||
};
|
|
||||||
acc.push(item);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
pfn()
|
pfn()
|
||||||
@ -674,24 +675,4 @@ macro_rules! until {
|
|||||||
($i:expr, $term:ident) => {
|
($i:expr, $term:ident) => {
|
||||||
consume_until!($i, run!($term))
|
consume_until!($i, run!($term))
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/// Maps a Result of type Vec<&u8> to a Result of type String.
|
|
||||||
pub fn must_string<'a, I, E>(matched: Result<I, Vec<&'a u8>>, msg: E) -> Result<I, String>
|
|
||||||
where
|
|
||||||
I: InputIter<Item=&'a u8>,
|
|
||||||
E: Into<String>,
|
|
||||||
{
|
|
||||||
match matched {
|
|
||||||
Result::Complete(i, mut o) => {
|
|
||||||
let new_string = String::from_utf8(o.drain(0..).map(|b| *b).collect());
|
|
||||||
match new_string {
|
|
||||||
Ok(s) => Result::Complete(i, s),
|
|
||||||
Err(_) => Result::Abort(Error::new(msg, &i)),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Result::Incomplete(offset) => Result::Incomplete(offset),
|
|
||||||
Result::Abort(e) => Result::Abort(e),
|
|
||||||
Result::Fail(e) => Result::Fail(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
85
src/iter.rs
85
src/iter.rs
@ -2,7 +2,7 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
use super::{InputIter, Offsetable};
|
use super::{InputIter, Offsetable, Span, SpanRange};
|
||||||
|
|
||||||
/// Implements `InputIter` for any slice of T.
|
/// Implements `InputIter` for any slice of T.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -21,10 +21,6 @@ impl<'a, T: Debug + 'a> SliceIter<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn str_iter<'a>(input: &'a str) -> SliceIter<'a, u8> {
|
|
||||||
SliceIter::new(input.as_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: Debug + 'a> Iterator for SliceIter<'a, T> {
|
impl<'a, T: Debug + 'a> Iterator for SliceIter<'a, T> {
|
||||||
type Item = &'a T;
|
type Item = &'a T;
|
||||||
|
|
||||||
@ -56,10 +52,20 @@ impl<'a, T: Debug + 'a> Clone for SliceIter<'a, T> {
|
|||||||
|
|
||||||
impl<'a, T: Debug + 'a> InputIter for SliceIter<'a, T> {}
|
impl<'a, T: Debug + 'a> InputIter for SliceIter<'a, T> {}
|
||||||
|
|
||||||
|
impl<'a, T: Debug + 'a> Span<&'a [T]> for SliceIter<'a, T> {
|
||||||
|
fn span(&self, idx: SpanRange) -> &'a [T] {
|
||||||
|
match idx {
|
||||||
|
SpanRange::Range(r) => self.source.index(r),
|
||||||
|
SpanRange::RangeTo(r) => self.source.index(r),
|
||||||
|
SpanRange::RangeFrom(r) => self.source.index(r),
|
||||||
|
SpanRange::RangeFull(r) => self.source.index(r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for SliceIter<'a, u8> {
|
impl<'a> From<&'a str> for SliceIter<'a, u8> {
|
||||||
fn from(source: &'a str) -> Self {
|
fn from(source: &'a str) -> Self {
|
||||||
str_iter(source)
|
SliceIter::new(source.as_bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,4 +79,71 @@ impl <'a, T: Debug> From<&'a Vec<T>> for SliceIter<'a, T> {
|
|||||||
fn from(source: &'a Vec<T>) -> Self {
|
fn from(source: &'a Vec<T>) -> Self {
|
||||||
SliceIter::new(source.as_slice())
|
SliceIter::new(source.as_slice())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements `InputIter` for any slice of T.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct StrIter<'a> {
|
||||||
|
source: &'a str,
|
||||||
|
offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> StrIter<'a> {
|
||||||
|
/// new constructs a StrIter from a Slice of T.
|
||||||
|
pub fn new(source: &'a str) -> Self {
|
||||||
|
StrIter {
|
||||||
|
source: source,
|
||||||
|
offset: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for StrIter<'a> {
|
||||||
|
type Item = &'a u8;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self.source.as_bytes().get(self.offset) {
|
||||||
|
Some(item) => {
|
||||||
|
self.offset += 1;
|
||||||
|
Some(item)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Offsetable for StrIter<'a> {
|
||||||
|
fn get_offset(&self) -> usize {
|
||||||
|
self.offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Clone for StrIter<'a> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
StrIter {
|
||||||
|
source: self.source,
|
||||||
|
offset: self.offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> InputIter for StrIter<'a> {}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for StrIter<'a> {
|
||||||
|
fn from(source: &'a str) -> Self {
|
||||||
|
Self::new(source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::ops::Index;
|
||||||
|
|
||||||
|
impl<'a> Span<&'a str> for StrIter<'a> {
|
||||||
|
fn span(&self, idx: SpanRange) -> &'a str {
|
||||||
|
match idx {
|
||||||
|
SpanRange::Range(r) => self.source.index(r),
|
||||||
|
SpanRange::RangeTo(r) => self.source.index(r),
|
||||||
|
SpanRange::RangeFrom(r) => self.source.index(r),
|
||||||
|
SpanRange::RangeFull(r) => self.source.index(r),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
12
src/lib.rs
12
src/lib.rs
@ -13,6 +13,18 @@ impl Offsetable for usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum SpanRange {
|
||||||
|
Range(std::ops::Range<usize>),
|
||||||
|
RangeTo(std::ops::RangeTo<usize>),
|
||||||
|
RangeFrom(std::ops::RangeFrom<usize>),
|
||||||
|
RangeFull(std::ops::RangeFull),
|
||||||
|
}
|
||||||
|
|
||||||
|
// An input that can provide a span of a range of the input.
|
||||||
|
pub trait Span<O> {
|
||||||
|
fn span(&self, idx: SpanRange) -> O;
|
||||||
|
}
|
||||||
|
|
||||||
/// A Cloneable Iterator that can report an offset as a count of processed Items.
|
/// A Cloneable Iterator that can report an offset as a count of processed Items.
|
||||||
pub trait InputIter: Iterator + Clone + Offsetable {}
|
pub trait InputIter: Iterator + Clone + Offsetable {}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
use super::{InputIter, Offsetable, Result};
|
use super::{InputIter, Offsetable, Result};
|
||||||
use iter::SliceIter;
|
use iter::{StrIter, SliceIter};
|
||||||
use combinators::must_string;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_slice_iter() {
|
fn test_slice_iter() {
|
||||||
@ -354,13 +353,13 @@ fn test_repeat_abort() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_until() {
|
fn test_until() {
|
||||||
let input_str = "foo; ";
|
let input_str = "foo; ";
|
||||||
let iter = SliceIter::new(input_str.as_bytes());
|
let iter = StrIter::new(input_str);
|
||||||
let result = must_string(until!(iter, text_token!("; ")), "AAAHHH!".to_string());
|
let result = until!(iter, text_token!("; "));
|
||||||
assert!(result.is_complete());
|
assert!(result.is_complete());
|
||||||
if let Result::Complete(i, o) = result {
|
if let Result::Complete(i, o) = result {
|
||||||
assert_eq!(i.get_offset(), 3);
|
assert_eq!(i.get_offset(), 3);
|
||||||
assert_eq!(o.len(), 3);
|
assert_eq!(o.len(), 3);
|
||||||
assert_eq!(&o, "foo");
|
assert_eq!(o, "foo");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user